LeetCode 468. 验证IP地址【c++/java详细题解】

309 阅读3分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战

1、题目

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。

  • 如果是有效的 IPv4 地址,返回 "IPv4"
  • 如果是有效的 IPv6 地址,返回"IPv6"
  • 如果不是上述类型的 IP 地址,返回 "Neither"

IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1

同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。

IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。

然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (::) 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。

同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

 输入:IP = "2001:0db8:85a3:0:0:8A2E:0370:7334:"
 输出:"Neither"

示例 5:

 输入:IP = "1e1.4.5.6"
 输出:"Neither"

提示:

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

2、思路

(字符串 + 模拟) O(n)O(n)

一个合法的IPv4满足以下条件:

  1. .分割成4组字符串。
  2. 每组字符串不为空,且长度<= 3
  3. 每组字符串转换成数字后介于0 ~ 255之间。
  4. 每组字符串仅由数字字符组成。
  5. 每组字符串的长度大于1时,不包含前导0

一个合法的IPv6满足以下条件:

  1. :分割成8组字符串。
  2. 每组字符串不为空,且长度<= 4
  3. 每组字符串转化成数字后为一个16进制数,即字符范围为: 0~9,a~f, A~F

由于C++中没有按字符分割的函数,因此我们自定义一个分割函数split,如下:

 vector<string> split(string ip, char t) {
         vector<string> items;
         for (int i = 0; i < ip.size(); i ++ ) {
             int j = i;
             string item;
             while (ip[j] != t) item += ip[j ++ ];
             i = j;
             items.push_back(item);
         }
         return items;
    } 

这里使用了双指针算法,传入一个要分割的字符串ip和分割字符t,最后返回分割好的字符串数组items

判断一个合法的IPv4和IPv6,我们首先调用分割函数split,然后按照上述条件模拟即可。

具体过程如下:

  • 1、如果一个字符串ip即包含.也包含:,我们直接返回Neither
  • 2、如果包含.,我们进行check_ipv4(ip),IPv4的合法性判断。
  • 3、如果包含:,我们进行check_ipv6(ip),IPv6的合法性判断。

时间复杂度分析: 每个字符串仅会被遍历一遍,因此时间复杂度为O(n)。

3、c++代码

 class Solution {
 public:
     vector<string> split(string ip, char t){
         vector<string> items;
         for(int i = 0; i < ip.size(); i++){
             int j = i;
             string item;
             while(j < ip.size() && ip[j] != t)  item += ip[j++];
             i = j;
             items.push_back(item);  
         }
         return items;
     }
     string check_ipv4(string ip){
         auto items = split(ip + '.', '.');a
         if(items.size() != 4) return "Neither";
         for(string item : items){
             if(item.empty() || item.size() > 3) return "Neither";
             if(item.size() > 1 && item[0] == '0')   return "Neither";
             for(char c : item){
                 if(c < '0' || c > '9') return "Neither";
             }
             int t = stoi(item);
             if(t > 255) return "Neither";
         }
         return "IPv4";
     }
     bool check(char c){
         if (c >= '0' && c <= '9') return true;
         if (c >= 'a' && c <= 'f') return true;
         if (c >= 'A' && c <= 'F') return true;
         return false;
     }
     string check_ipv6(string ip){
         auto items = split(ip + ':', ':');
         if(items.size() != 8) return "Neither";
         for(string item : items){
             if(item.empty() || item.size() > 4) return "Neither";
             for(char c : item){
                 if(!check(c)) return "Neither"; 
             }
         }
         return "IPv6";
     }
 ​
     string validIPAddress(string ip) {
         if(ip.find('.') != -1 && ip.find(':') != -1) return "Neither";
         if(ip.find('.') != -1)  return check_ipv4(ip);
         if(ip.find(':') != -1)  return check_ipv6(ip);
         return "Neither";
     }
 };

4、Java代码

class Solution {
    public String validIPAddress(String IP) {
        if (IP == null || IP.length() == 0) return "Neither";
        if (isIPv4(IP)) return "IPv4";
        if (isIPv6(IP)) return "IPv6";
        return "Neither";
    }

    public boolean isIPv4(String IP){
        String[] ips = IP.split("\\.");
        if (ips.length != 4) return false;
        if (IP.charAt(0) == '.' || IP.charAt(IP.length()-1) == '.') return false;
        for (int i = 0 ; i < ips.length ; i ++)
            if (!isIPv4Group(ips[i])) return false;
        return true;
    }

    private boolean isIPv4Group(String IPG){
        if (IPG == null || IPG.length() == 0 || IPG.length() > 3) return false;
        for (int i = 0 ; i < IPG.length();  i++)
            if (!('0' <= IPG.charAt(i) && IPG.charAt(i) <= '9'))  return false;
        int x = Integer.valueOf(IPG);
        if (x< 0 || x > 255 || (IPG.charAt(0) == '0' && IPG.length() > 1))
            return false;
        return true;
    }

    public boolean isIPv6(String IP){
        String[] ips = IP.split(":");
        if (ips.length != 8) return false;
        if (IP.charAt(0) == ':' || IP.charAt(IP.length()-1) == ':') return false;
        for (int i = 0 ; i < ips.length ; i ++){

            if (!isIPv6Group(ips[i])) return false;
        }
        return true;
    }

    private boolean isIPv6Group(String IPG){
        if (IPG == null || IPG.length() == 0 || IPG.length() > 4) return false;
        for (int i = 0 ; i < IPG.length(); i++) 
            if (!('0' <= IPG.charAt(i) && IPG.charAt(i) <= '9' || 'a' <= IPG.charAt(i) && IPG.charAt(i) <= 'f' || 'A' <= IPG.charAt(i) && IPG.charAt(i) <='F'))
                return false;
        return true;
    }
}