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地址。
解题思路:
判断IP类型:如果包含 ‘.’,可能是IPv4;如果包含 ‘:’,可能是IPv6;如果两者都包含或都不包含,则无效。
IPv4验证:
- 必须恰好有4个部分,用 ‘.’ 分隔
- 每个部分必须是1-3位数字
- 数值范围在0-255之间
- 不能有前导零(除非是单个字符"0")
- 不能包含非数字字符
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]
复杂度分析
| 复杂度 | IPv4 | IPv6 |
|---|---|---|
| 时间复杂度 | O(1) | O(1) |
| 空间复杂度 | O(1) | O(1) |
说明:
- 时间复杂度:O(1) - IP地址的长度是固定的(IPv4最多15个字符,IPv6最多39个字符),所以时间复杂度为常数
- 空间复杂度:O(1) - 只使用了固定大小的额外空间来存储分割后的字符串数组
相关题目
. IP to CIDR (Medium)
. Strong Password Checker II (Easy)