题目描述
// 93. 复原 IP 地址
// 给定一个只包含数字的字符串,用以表示一个 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 地址。
题解
// 回溯搜索
// 难就难在边界条件很多。递归最重要的是知道语义,我们就抓住语义来写。
// 我们定义答案保存位res,定义回溯搜索函数backtracking,定义下一次递归的遍历
// 字符串起点为start,初始化为0。定义记录ip地址组合的临时字符组path。
//
// backtracking函数:
// 首先ip地址最多被"."分成四段,如果递归的时候遇到path.size()大于4,不合规,
// 直接return。如果遇到path.size()大于等于4,且遍历字符串的指针起点start居然没到达
// String s的末位,不合规,直接return。否则,如果path.size()等于4,则将path当中记录的字符串ip,按照"."连接成String,
// 存入res,并返回。
// for循环遍历String s的字符串子串,遍历子串起点为start,右指针为i。
// 截取的字符串子串记为newstr = s.sbustring(start, i+1),如果子串超过了
// 3,或者以“0”开头时,不合规,直接break。
// 取字符串子串newstr转为整型value,如果数值小于0或者大于255,不合规,直接
// break。
// 如果不合规情况都不满足,直接将newstr加入path,再次递归调用backtracking
// 此时遍历起始点start更新为i + 1,即:接着newstr子串之后的子串。
// 递归返回之后删掉path中之前存入的newstr。
//
// 执行用时:3 ms, 在所有 Java 提交中击败了60.99%的用户
// 内存消耗:38.2 MB, 在所有 Java 提交中击败了77.37%的用户
class Solution {
List<String> res;
public List<String> restoreIpAddresses(String s) {
this.res = new ArrayList<>();
backtracking(s, 0, new ArrayList<>());
return res;
}
private void backtracking(String s, int start, List<String> path) {
if (path.size() > 4) {
return;
}
if (path.size() >= 4 && start != s.length()) {
return;
}
if (path.size() == 4) {
res.add(String.join(".", path));
return;
}
for (int i = start; i < s.length(); i++) {
String newstr = s.substring(start, i + 1);
if (newstr.length() > 3 || newstr.length() > 1 && newstr.startsWith("0")) {
break;
}
int value = Integer.valueOf(newstr);
if (value < 0 || value > 255) {
break;
}
path.add(newstr);
backtracking(s, i + 1, path);
path.remove(path.size() - 1);
}
}
}