Medium

题目描述

给定一个字符串 queryIP,如果IP是有效的IPv4地址,返回 “IPv4”;如果IP是有效的IPv6地址,返回 “IPv6”;如果IP不是任何类型的正确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”、“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 仅由英文字母、数字以及字符 ‘.’ 和 ‘:’ 组成。

解题思路

这道题需要分别验证IPv4和IPv6地址的格式。我们可以通过分析字符串中的分隔符来判断是哪种类型的IP地址。

解题思路:

  1. 判断IP类型:如果包含 ‘.’,可能是IPv4;如果包含 ‘:’,可能是IPv6;如果两者都包含或都不包含,则无效。

  2. IPv4验证

    • 必须恰好有4个部分,用 ‘.’ 分隔
    • 每个部分必须是1-3位数字
    • 数值范围在0-255之间
    • 不能有前导零(除非是单个字符"0")
    • 不能包含非数字字符
  3. IPv6验证

    • 必须恰好有8个部分,用 ‘:’ 分隔
    • 每个部分长度在1-4之间
    • 只能包含十六进制字符(0-9, a-f, A-F)
    • 允许前导零

实现细节:

  • 使用字符串分割函数将IP地址按分隔符分割
  • 分别编写验证IPv4和IPv6各部分的辅助函数
  • 注意边界条件,如空字符串、只有分隔符等情况

推荐使用字符串处理的方法,代码清晰易懂,且能够准确处理各种边界情况。

代码实现

class Solution {
public:
    string validIPAddress(string queryIP) {
        if (queryIP.find('.') != string::npos) {
            return isValidIPv4(queryIP) ? "IPv4" : "Neither";
        } else if (queryIP.find(':') != string::npos) {
            return isValidIPv6(queryIP) ? "IPv6" : "Neither";
        }
        return "Neither";
    }
    
private:
    bool isValidIPv4(string ip) {
        vector<string> parts = split(ip, '.');
        if (parts.size() != 4) return false;
        
        for (string part : parts) {
            if (!isValidIPv4Part(part)) return false;
        }
        return true;
    }
    
    bool isValidIPv6(string ip) {
        vector<string> parts = split(ip, ':');
        if (parts.size() != 8) return false;
        
        for (string part : parts) {
            if (!isValidIPv6Part(part)) return false;
        }
        return true;
    }
    
    bool isValidIPv4Part(string part) {
        if (part.empty() || part.length() > 3) return false;
        if (part[0] == '0' && part.length() > 1) return false;
        
        for (char c : part) {
            if (!isdigit(c)) return false;
        }
        
        int num = stoi(part);
        return num >= 0 && num <= 255;
    }
    
    bool isValidIPv6Part(string part) {
        if (part.empty() || part.length() > 4) return false;
        
        for (char c : part) {
            if (!isdigit(c) && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) {
                return false;
            }
        }
        return true;
    }
    
    vector<string> split(string str, char delimiter) {
        vector<string> result;
        stringstream ss(str);
        string item;
        
        while (getline(ss, item, delimiter)) {
            result.push_back(item);
        }
        return result;
    }
};
class Solution:
    def validIPAddress(self, queryIP: str) -> str:
        if '.' in queryIP:
            return "IPv4" if self.isValidIPv4(queryIP) else "Neither"
        elif ':' in queryIP:
            return "IPv6" if self.isValidIPv6(queryIP) else "Neither"
        return "Neither"
    
    def isValidIPv4(self, ip: str) -> bool:
        parts = ip.split('.')
        if len(parts) != 4:
            return False
        
        for part in parts:
            if not self.isValidIPv4Part(part):
                return False
        return True
    
    def isValidIPv6(self, ip: str) -> bool:
        parts = ip.split(':')
        if len(parts) != 8:
            return False
        
        for part in parts:
            if not self.isValidIPv6Part(part):
                return False
        return True
    
    def isValidIPv4Part(self, part: str) -> bool:
        if not part or len(part) > 3:
            return False
        if part[0] == '0' and len(part) > 1:
            return False
        
        if not part.isdigit():
            return False
        
        num = int(part)
        return 0 <= num <= 255
    
    def isValidIPv6Part(self, part: str) -> bool:
        if not part or len(part) > 4:
            return False
        
        for c in part:
            if not (c.isdigit() or 'a' <= c.lower() <= 'f'):
                return False
        return True
public class Solution {
    public string ValidIPAddress(string queryIP) {
        if (queryIP.Contains('.')) {
            return IsValidIPv4(queryIP) ? "IPv4" : "Neither";
        } else if (queryIP.Contains(':')) {
            return IsValidIPv6(queryIP) ? "IPv6" : "Neither";
        }
        return "Neither";
    }
    
    private bool IsValidIPv4(string ip) {
        string[] parts = ip.Split('.');
        if (parts.Length != 4) return false;
        
        foreach (string part in parts) {
            if (!IsValidIPv4Part(part)) return false;
        }
        return true;
    }
    
    private bool IsValidIPv6(string ip) {
        string[] parts = ip.Split(':');
        if (parts.Length != 8) return false;
        
        foreach (string part in parts) {
            if (!IsValidIPv6Part(part)) return false;
        }
        return true;
    }
    
    private bool IsValidIPv4Part(string part) {
        if (string.IsNullOrEmpty(part) || part.Length > 3) return false;
        if (part[0] == '0' && part.Length > 1) return false;
        
        foreach (char c in part) {
            if (!char.IsDigit(c)) return false;
        }
        
        int num = int.Parse(part);
        return num >= 0 && num <= 255;
    }
    
    private bool IsValidIPv6Part(string part) {
        if (string.IsNullOrEmpty(part) || part.Length > 4) return false;
        
        foreach (char c in part) {
            if (!char.IsDigit(c) && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) {
                return false;
            }
        }
        return true;
    }
}
var validIPAddress = function(queryIP) {
    if (queryIP.includes('.')) {
        return isValidIPv4(queryIP) ? "IPv4" : "Neither";
    } else if (queryIP.includes(':')) {
        return isValidIPv6(queryIP) ? "IPv6" : "Neither";
    }
    return "Neither";
    
    function isValidIPv4(ip) {
        const parts = ip.split('.');
        if (parts.length !== 4) return false;
        
        for (const part of parts) {
            if (!isValidIPv4Part(part)) return false;
        }
        return true;
    }
    
    function isValidIPv6(ip) {
        const parts = ip.split(':');
        if (parts.length !== 8) return false;
        
        for (const part of parts) {
            if (!isValidIPv6Part(part)) return false;
        }
        return true;
    }
    
    function isValidIPv4Part(part) {
        if (!part || part.length > 3) return false;
        if (part[0]

复杂度分析

复杂度IPv4IPv6
时间复杂度O(1)O(1)
空间复杂度O(1)O(1)

说明:

  • 时间复杂度:O(1) - IP地址的长度是固定的(IPv4最多15个字符,IPv6最多39个字符),所以时间复杂度为常数
  • 空间复杂度:O(1) - 只使用了固定大小的额外空间来存储分割后的字符串数组

相关题目