题目链接:
https://leetcode-cn.com/problems/restore-ip-addresses/
给定一个只包含数字的字符串,复原它并返回所有可能的 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:
- 输入:s = "25525511135"
- 输出:["255.255.11.135","255.255.111.35"]
示例 2:
- 输入:s = "0000"
- 输出:["0.0.0.0"]
示例 3:
- 输入:s = "1111"
- 输出:["1.1.1.1"]
示例 4:
- 输入:s = "010010"
- 输出:["0.10.0.10","0.100.1.0"]
示例 5:
- 输入:s = "101023"
- 输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
提示:
- 0 <= s.length <= 3000
- s 仅由数字组成
解析:
这一道题跟131.分割回文串(https://leetcode-cn.com/problems/palindrome-partitioning/)差不多,只不过是判断的条件不同而已,处理的思路都是一样的,递归回溯处理特定区间。这种涉及回溯的图可以将题目抽象成树结构方便解题,树的图片如下:
上图摘自《代码随想录》
可以采用递归四部曲:
递归作用:讨论以startIndex为起始点和带着pointNum数量的"."的子串是否为合格的IP地址
递归参数:startIndex为这一层要判断的子串的起点,pointNum是点号的个数
终止条件:pointNum == 3,点号足够的情况下再判断最后一段是否符合条件
单层逻辑:从startIndex开始取区间[startIndex, i]作为子串,最多取三个,看是否满足IP子串条件,满足条件则以i+1为起点取下一个子串,直至终止。
回溯算法最大的特点就是在这一层操作完后要对状态量进行初始化
代码如下:
class Solution {
List<String> result = null;
String path = null;
void restoreIpAddresses1(String s, int startIndex, int pointNum){
//递归作用:讨论以startIndex为起始点和带着pointNum数量的"."的子串是否为合格的IP地址
//递归参数:startIndex为这一层要判断的子串的起点,pointNum是点号的个数
//终止条件:pointNum == 3,点好足够的情况下再判断最后一段是否符合条件
//单层逻辑:从startIndex开始取区间[startIndex, i]作为子串,最多取三个,看是否满足IP子串条件,满足条件则以i+1为起点取下一个子串,直至终止。
if(pointNum == 3){
if(!isValid(s, startIndex, s.length() - 1)) return;
else path += s.substring(startIndex, s.length());
//result添加path
result.add(path);
path = path.substring(0, startIndex + 3);//回溯,初始化状态量
return;
}
for(int i = startIndex; i < startIndex + 3 && i < s.length() - 1; i++){//从startIndex开始取区间[startIndex, i]作为子串,最多取三个,看是否满足IP子串条件,满足条件则以i+1为起点取下一个子串
//判断s中的[startIndex, i]是否符合条件,符合就添加到path并取下一层
if(isValid(s, startIndex, i)){
path += s.substring(startIndex, i + 1);
path += ".";
restoreIpAddresses1(s, i + 1, pointNum + 1);
path = path.substring(0, startIndex + pointNum);//回溯
}
}
}
boolean isValid(String s, int begin, int end){//判断所取区间是否满足条件,区间是左闭右闭
if(end - begin > 0 && s.charAt(begin) == '0') return false;//排除前导0
int temp = 0;
for(int i = begin; i <= end; i++)
temp = temp * 10 + s.charAt(i) - '0';
if(temp > 255) return false;
return true;
}
public List<String> restoreIpAddresses(String s) {
result = new ArrayList<>();
path = new String();
if(s.length() > 12) return result;//剪枝操作
restoreIpAddresses1(s, 0, 0);
return result;
}
}