文章目录
一、题目
给定一个只包含数字的字符串,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。
例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “192.168@1.1” 是 无效 IP 地址。
二、回溯分析
该题和 分割回文串 类似,也可以看作是组合问题,然后判定每个子字符串是否符合要求
(1)确定递归参数
因为符合条件的子字符串需要给其加
"."
,回溯时,也需要删除这个"."
,所以采用 StringBuilder 来操作
需要的参数有,字符串s,切割的起始下标 startIndex(防止重复),记录添加逗点的pointNum
(2)递归终止条件
当
pointNum==3
时,表示IP地址组成,此时需要判断第四段也就是(startIndex,sb.length()-1)
是否符合要求,符合则进行记录
//逗号数量为3时,结束分隔
if (pointNum == 3) {
//判断第四段子字符串是否合法
if (isValid(sb.toString(), startIndex, sb.length() - 1)) {
list.add(sb.toString());
}
}
(3)确定回溯搜索过程
startIndex 表示下一轮递归遍历的起始位置,也可以看作切割线
在for (int i = startIndex; i < s.length(); i++)
循环中,我们 定义了起始位置startIndex
,那么[startIndex, i]
就是要截取的子串
判断这个子串是否符合要求
判断是否符合要求:
IP段为0开头的数字不合法
IP段有非正整数字符不合法
IP段大于255不合法
//判断子字符串是否合法
private boolean isValid(String s, int start, int end) {
if (start > end) {
return false;
}
//0开头的数字不合法
if (s.charAt(start) == '0' && start != end) {
return false;
}
int num = 0;
for (int i = start; i <= end; i++) {
if (s.charAt(i) > '9' || s.charAt(i) < '0') {
return false;
}
num = num * 10 + s.charAt(i) - '0';
if (num > 255) {
return false;
}
}
return true;
}
三、代码
class Solution {
List<String> list = new ArrayList<>();
StringBuilder sb = new StringBuilder();
public List<String> restoreIpAddresses(String s) {
//长度不够,或者超出范围直接返回
if (s.length() < 4 || s.length() > 12) {
return list;
}
//方便操作,将 String 转为 StringBuilder
sb.append(s);
backTracking(sb, 0, 0);
return list;
}
private void backTracking(StringBuilder sb, int startIndex, int pointNum) {
//逗号数量为3时,结束分隔
if (pointNum == 3) {
//判断第四段子字符串是否合法
if (isValid(sb.toString(), startIndex, sb.length() - 1)) {
list.add(sb.toString());
}
}
for (int i = startIndex; i < sb.length(); i++) {
if (isValid(sb.toString(), startIndex, i)) {
//在i的后面插入一个逗点
sb.insert(i + 1, ".");
//插入逗点后,下一个子串的起始位置为i+2
backTracking(sb, i + 2, ++pointNum);
//回溯删掉逗点
pointNum--;
sb.deleteCharAt(i + 1);
} else {
break;
}
}
}
//判断子字符串是否合法
private boolean isValid(String s, int start, int end) {
if (start > end) {
return false;
}
//0开头的数字不合法
if (s.charAt(start) == '0' && start != end) {
return false;
}
int num = 0;
for (int i = start; i <= end; i++) {
if (s.charAt(i) > '9' || s.charAt(i) < '0') {
return false;
}
num = num * 10 + s.charAt(i) - '0';
if (num > 255) {
return false;
}
}
return true;
}
}
四、总结
同切割问题,类似组合,需要对每一种组合进行判断是否符合要求