验证IP地址

标签: 字符串

难度: Medium

给定一个字符串 queryIP。如果是有效的 IPv4 地址,返回 "IPv4" ;如果是有效的 IPv6 地址,返回 "IPv6" ;如果不是上述类型的 IP 地址,返回 "Neither"

有效的IPv4地址“x1.x2.x3.x4” 形式的IP地址。 其中 0 <= xi <= 255 且 xi 不能包含 前导零。例如: “192.168.1.1” 、 “192.168.1.0” 为有效IPv4地址, “192.168.01.1” 为无效IPv4地址; “192.168.1.00”“192.168@1.1” 为无效IPv4地址。

一个有效的IPv6地址 是一个格式为“x1:x2:x3:x4:x5:x6:x7:x8” 的IP地址,其中:

  • 1 <= xi.length <= 4
  • xi 是一个 十六进制字符串 ,可以包含数字、小写英文字母( 'a''f' )和大写英文字母( 'A''F' )。
  • 在 xi 中允许前导零。

例如 "2001:0db8:85a3:0000:0000:8a2e:0370:7334""2001:db8:85a3:0:0:8A2E:0370:7334" 是有效的 IPv6 地址,而 "2001:0db8:85a3::8A2E:037j:7334""02001:0db8:85a3:0000:0000:8a2e:0370:7334" 是无效的 IPv6 地址。

示例 1:

输入:queryIP = "172.16.254.1"
输出:"IPv4"
解释:有效的 IPv4 地址,返回 "IPv4"

示例 2:

输入:queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334"
输出:"IPv6"
解释:有效的 IPv6 地址,返回 "IPv6"

示例 3:

输入:queryIP = "256.256.256.256"
输出:"Neither"
解释:既不是 IPv4 地址,又不是 IPv6 地址

提示:

  • queryIP 仅由英文字母,数字,字符 '.'':' 组成。

Submission

运行时间: 24 ms

内存: 0.0 MB

class Solution:
    def validIPAddress(self, IP: str) -> str:
        
        def isIpv4(s):
            try:
                return str(int(s)) == s and 0<=int(s)<=255
            except:
                return False
        
        def isIpv6(s):
            try:
                return 1<=len(s)<=4 and int(s, 16)>=0
            except:
                return False
        
        if IP.count(".")== 3 and all(isIpv4(s) for s in IP.split(".")):
            return "IPv4"
        if IP.count(":")== 7 and all(isIpv6(s) for s in IP.split(":")):
            return "IPv6"
        return "Neither"
        

Explain

这个题解的思路是分别判断给定的字符串是否为有效的IPv4地址或IPv6地址。对于IPv4地址,先判断字符串中'.'的数量是否为3,然后对用'.'分割的每一段进行判断,要求每一段都能转换为0-255之间的整数且转换后的字符串与原字符串相等(以避免01这样的情况)。对于IPv6地址,先判断字符串中':'的数量是否为7,然后对用':'分割的每一段进行判断,要求每一段为1-4个字符,且能转换为非负的16进制整数。如果既不满足IPv4也不满足IPv6的条件,就返回'Neither'。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def validIPAddress(self, IP: str) -> str:
        
        def isIpv4(s):
            try:
                # 判断每一段是否为0-255的整数
                return str(int(s)) == s and 0<=int(s)<=255 
            except:
                return False
        
        def isIpv6(s):
            try:
                # 判断每一段是否为1-4个字符的非负16进制整数
                return 1<=len(s)<=4 and int(s, 16)>=0
            except:
                return False
        
        if IP.count(".")== 3 and all(isIpv4(s) for s in IP.split(".")):
            # 判断是否满足IPv4的条件
            return "IPv4"
        if IP.count(":")== 7 and all(isIpv6(s) for s in IP.split(":")): 
            # 判断是否满足IPv6的条件
            return "IPv6"
        return "Neither"
        

Explore

这种检查方法用来确保字符串段不包含前导零或非数字字符。例如,'01'或'001'虽然数值上等同于'1',但不是有效的IPv4地址部分,因为标准IPv4地址格式不允许单个段有前导零。此外,这种比较确保字符串段不含非数字字符,这是因为尝试将非纯数字的字符串转换为整数会失败。

在Python中,可以通过尝试将字符串使用`int(s, 16)`转换为整数来检查其是否为有效的十六进制数。这里的'16'表示转换的基数是16。如果转换过程中没有引发异常,且得到的整数是非负的,那么这个字符串就是有效的十六进制数。

IPv6地址中每一部分的长度限制为1到4个字符,主要是为了确保每一部分都在有效的十六进制整数范围内。长度限制避免了解析错误和范围超出问题,因为十六进制数超过4个字符可能代表的数值会超出IPv6每段允许的最大值FFFF(即65535十进制)。

使用split操作分割字符串时,如果遇到连续的分隔符,会生成空字符串作为分割结果的一部分。例如,对于IPv4地址,如果输入字符串为'192..168.1',使用`.`分割后会得到['192', '', '168', '1'],其中一个分割结果为空字符串,这不符合IPv4地址的格式要求。因此,这种情况下的输入会被判定为无效地址。