Given a string queryIP
, return "IPv4"
if IP is a valid IPv4 address, "IPv6"
if IP is a valid IPv6 address or "Neither"
if IP is not a correct IP of any type.
A valid IPv4 address is an IP in the form "x1.x2.x3.x4"
where 0 <= xi <= 255
and xi
cannot contain leading zeros. For example, "192.168.1.1"
and "192.168.1.0"
are valid IPv4 addresses while "192.168.01.1"
, "192.168.1.00"
, and "192.168@1.1"
are invalid IPv4 addresses.
A valid IPv6 address is an IP in the form "x1:x2:x3:x4:x5:x6:x7:x8"
where:
1 <= xi.length <= 4
xi
is a hexadecimal string which may contain digits, lowercase English letter ('a'
to 'f'
) and upper-case English letters ('A'
to 'F'
).xi
.For example, "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
and "2001:db8:85a3:0:0:8A2E:0370:7334"
are valid IPv6 addresses, while "2001:0db8:85a3::8A2E:037j:7334"
and "02001:0db8:85a3:0000:0000:8a2e:0370:7334"
are invalid IPv6 addresses.
Example 1:
Input: queryIP = "172.16.254.1" Output: "IPv4" Explanation: This is a valid IPv4 address, return "IPv4".
Example 2:
Input: queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334" Output: "IPv6" Explanation: This is a valid IPv6 address, return "IPv6".
Example 3:
Input: queryIP = "256.256.256.256" Output: "Neither" Explanation: This is neither a IPv4 address nor a IPv6 address.
Constraints:
queryIP
consists only of English letters, digits and the characters '.'
and ':'
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy involves testing the input string against two distinct sets of rules, one for each type of IP address. We first try to validate it as an IPv4 address by exhaustively checking every rule. If that fails, we then try to validate it as an IPv6 address, again by checking all of its specific rules.
Here's how the algorithm would work step-by-step:
class Solution:
def validIPAddress(self, queryIP: str) -> str:
ipv4_components = queryIP.split('.')
# An IPv4 address must be composed of exactly four numerical components separated by dots.
if len(ipv4_components) == 4:
is_valid_ipv4_format = True
for ipv4_component in ipv4_components:
if not ipv4_component.isdigit():
is_valid_ipv4_format = False
break
# Leading zeros are disallowed because they can be ambiguous, except for "0" itself.
if len(ipv4_component) > 1 and ipv4_component[0] == '0':
is_valid_ipv4_format = False
break
if not 0 <= int(ipv4_component) <= 255:
is_valid_ipv4_format = False
break
if is_valid_ipv4_format:
return "IPv4"
ipv6_components = queryIP.split(':')
# If IPv4 fails, check for IPv6, which has eight 1-4 digit hexadecimal components.
if len(ipv6_components) == 8:
is_valid_ipv6_format = True
for ipv6_component in ipv6_components:
if not (1 <= len(ipv6_component) <= 4):
is_valid_ipv6_format = False
break
for hex_character in ipv6_component:
if hex_character not in "0123456789abcdefABCDEF":
is_valid_ipv6_format = False
break
if not is_valid_ipv6_format:
break
if is_valid_ipv6_format:
return "IPv6"
return "Neither"
The approach is to first determine if the address looks like an IPv4 (with dots) or an IPv6 (with colons). Then, we break the address into its parts based on that separator and meticulously check if each part follows the strict rules for that specific address type.
Here's how the algorithm would work step-by-step:
class Solution:
def validIPAddress(self, query_ip: str) -> str:
# A '.' indicates a potential IPv4 address, so we attempt to validate it as such first.
if '.' in query_ip:
ipv4_parts = query_ip.split('.')
if len(ipv4_parts) != 4:
return "Neither"
for part in ipv4_parts:
# Each IPv4 segment must be a number from 0-255 and not have ambiguous leading zeros.
if not part.isdigit():
return "Neither"
if len(part) > 1 and part.startswith('0'):
return "Neither"
if not 0 <= int(part) <= 255:
return "Neither"
return "IPv4"
# If it's not IPv4, a ':' indicates a potential IPv6 address.
elif ':' in query_ip:
ipv6_parts = query_ip.split(':')
if len(ipv6_parts) != 8:
return "Neither"
valid_hex_characters = "0123456789abcdefABCDEF"
for part in ipv6_parts:
# Each IPv6 segment must be 1-4 valid hexadecimal characters.
if not (1 <= len(part) <= 4):
return "Neither"
for character in part:
if character not in valid_hex_characters:
return "Neither"
return "IPv6"
return "Neither"
Case | How to Handle |
---|---|
String with leading, trailing, or consecutive delimiters (e.g., '.1.2.3.4', '1.2.3.4.', '1..2.3.4'). | Splitting the string by the delimiter will produce empty parts, which must be rejected by component validation checks. |
An IPv4 component with a leading zero, such as '01', which is invalid. | The solution must explicitly check if a component has a length greater than one and starts with '0'. |
An incorrect number of components for either format (e.g., 3 for IPv4 or 9 for IPv6). | The length of the array after splitting the string must be exactly 4 for IPv4 or 8 for IPv6. |
An IPv4 component that is numerically outside the valid 0-255 range (e.g., '256' or '-1'). | After parsing a component as a number, its value must be checked to be within the inclusive [0, 255] range. |
An IPv6 component with zero characters or more than four characters (e.g., 'fffff'). | Each component's length must be validated to be between 1 and 4 characters inclusive. |
A component contains non-digit characters for IPv4 or non-hexadecimal characters for IPv6. | The validation logic for each component must strictly enforce the allowed character sets. |
Input string contains both '.' and ':' delimiters. | A preliminary check can quickly identify and reject strings containing both types of separators. |
The empty string or a string with just a delimiter as input. | The solution should handle these gracefully by returning 'Neither' without causing errors. |