nc113. 验证IP地址
题意
给你一个字符串,判定是不是合法的IPV4,IPV6的地址,或者都不是。
1. 直接模拟
根据题意注意下实现细节即可。
IPV4字符串有以下判断要点:
- 被点切割后的数组长度必须为4
- 数组中每个元素都是数字,大小范围是0~255之间
- (这里wa了一次)不能出现前导0!!!
IPV6字符串中有以下判断要点:
- 被冒号切割后的数组长度必须为8
- 数组中每个元素都是1-4位的十六进制字符串,允许大小写混合
- 可以出现前导0!!!!
如果本题用C++实现,还有一个难点就是split函数,在标准库中不存在split,所以我们要手写一个简易的split。手写split是一个典型的快慢指针问题, split的实现思路:
- 定义两个指针,start和end
- 从头开始遍历字符串,如果遇到了分割符,将start到end之间的字符串加入数组,并重置start和end为分隔符的下一位置,否则end++;
- 字符串遍历完如果还剩一段,即start未指向字符串末尾,则把最后一块加入数组。
split的过程如下图所示,以"192.168.1.123"为例:
- end一起右移,遇到点,则记录start到end之间的子串加入res,此时
res=["192"] - 加入后,
start=end+1, 开始遍历下一块。并且end继续右移。 - end又遇到了一个点,重复步骤1. 直到end走完。此时
res= ["192", "168", "1"] - while循环退出,发现start未指向字符串最尾端,说明还剩一段,加入到res, 此时执行
res.push_back("123").
class Solution {
public:
// 自己写的split函数
vector<string> split(string s, char ch) {
int start=0, end=0;
vector<string> res;
while (end < s.length()) {
// 快指针遇到分隔符,记录下当前块内容,然后两个指针同时从下一块开始
if (s[end] == ch) {
res.push_back(s.substr(start, end-start));
start = end+1;
}
// end指针一直右移
end++;
}
// 对最后一块的处理
if (start < s.length())
res.push_back(s.substr(start, end-start));
return res;
}
bool isIPV4(string &ip) {
vector<string> strs = split(ip, '.');
// 不是4个元素,是错误答案
if (strs.size() != 4) return false;
for (auto str : strs) {
int n = 0; // 记录每一块的数字
// 不能有前导0
if (str.size() > 0 && str[0] == '0')
return false;
for (auto c : str) {
// 出现了非数字,直接返回错误
if (!isdigit(c)) return false;
n = n*10 + (c-'0');
}
// 判断是不是在0-255之间,确保n是正数了
if (n > 255) return false;
}
return true;
}
bool isIPV6(string &ip) {
vector<string> strs = split(ip, ':');
// 判断长度是否为8
if (strs.size() != 8) return false;
for (auto str : strs) {
int n = str.size();
// 每段长度在1-4之间
if (n < 1 || n > 4) return false;
for (auto c : str) {
// 每一段都由16进制字符组成,大小写任意
if (!(isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' || c <= 'f')))
return false;
}
}
return true;
}
string solve(string IP) {
if (isIPV4(IP)) return "IPv4";
else if (isIPV6(IP)) return "IPv6";
return "Neither";
}
};- 时间复杂度:对于长度为n的字符串IP,先进行了split切分,再遍历,计算量均与n成正比,所以是
.
- 空间复杂度:用到了切分后的数组res,res的长度也与n成正比,所以空间也是
.
2. 用正则表达式
IPv4的正则表达式:
- 每一段里面是0~255的数字,分别讨论2开头(
2[0-4]\d|25[0-5]),1开头(1\d\d),两位数([1-9]\d),1位数(\d)的情况 - 每一段后面加一个点,构成一个整体,重复3次
- 后面再加上那一段
IPv6的正则表达式:
- 每一段都是1-4位的16进制字符,用
[\da-fA-F]表示 - 加上冒号重复七遍,再加上最后一段
因为cpp中没有正则库,故方法二换用Java实现。
import java.util.*;
import java.util.regex.Pattern;
public class Solution {
/**
* 验证IP地址
* @param IP string字符串 一个IP地址字符串
* @return string字符串
*/
public String solve (String IP) {
String ipv4 = "^((2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]\\d|\\d)\\.){3}(2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]\\d|\\d)$";
String ipv6 = "^(([\\da-fA-F]{1,4}):){7}([\\da-fA-F]{1,4})$";
if (Pattern.matches(ipv4, IP)) return "IPv4";
else if (Pattern.matches(ipv6, IP)) return "IPv6";
return "Neither";
}
}- 时间复杂度:正则匹配的时间复杂度也是
,因为可以认为是一个自动机,在长度为n的串上进行转移。但是常数远大于方法一
- 空间复杂度:
.

京公网安备 11010502036488号