从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。
例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “[email protected]” 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
示例 1:
输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]
示例 2:
输入:s = “0000”
输出:[“0.0.0.0”]
示例 3:
输入:s = “101023”
输出:[“1.0.10.23”,“1.0.102.3”,“10.1.0.23”,“10.10.2.3”,“101.0.2.3”]
提示:
1 <= s.length <= 20
s 仅由数字组成
解题思路
本题使用回溯和递归的思想复原 ip 地址 .
首先创建 ans 来接收复原后的所有 ip 地址,然后通过创建回溯方法进行筛选,最终返回 ans。
创建回溯方法体需要传入四个参数进行把控:1.给定的数字字符串 s,2.回溯过程中遍历到的位置 pos,3.当前确定好的 ip 段的数量,4.收集结果的 ans
考虑方法体出口:如果确定好 4 段并且遍历完整个 s,就将 tmp 之间的段以 . 分隔开来放入 ans
接下来对 s 进行筛选,其中注意每段的长度最大为 3,拆箱为 int 后的长度不超过 255,起始位置不能为 0
控制好这些边界条件后就可以就可以正常的利用递归和回溯遍历字符串,具体可参考代码注释。
代码
class Solution {
public List restoreIpAddresses(String s) {
List ans = new ArrayList<>();
if (s == null || s.length() == 0) {
return ans;
}
backtrack(s, ans, 0, new ArrayList<>());
return ans;
}
// pos-当前遍历到 s 字符串中的位置,tmp-当前存放已经确定好的 ip 段的数量
private void backtrack(String s, List ans, int pos, List tmp) {
if (tmp.size() == 4) {
// 如果此时 pos 也刚好遍历完整个 s
if (pos == s.length()) {
// join 用法:例如 [[255],[255],[111],[35]] -> 255.255.111.35
ans.add(String.join(".", tmp));
}
// 否则直接返回
return;
}
// ip 地址每段最多有三个数字
for (int i = 1; i <= 3; i++) {
// 如果当前位置距离 s 末尾小于 3 就不用再分段了,直接跳出循环即可。
if (pos + i > s.length()) {
break;
}
// 将 s 的子串开始分段
String segment = s.substring(pos, pos + i);
int val = Integer.valueOf(segment);
// 剪枝条件:段的起始位置不能为 0,段拆箱成 int 类型的长度不能大于 255
if (segment.startsWith("0") && segment.length() > 1 || (i == 3 && val > 255)) {
continue;
}
// 符合要求就加入到 tmp 中
tmp.add(segment);
// 继续递归遍历下一个位置
backtrack(s, ans, pos + i, tmp);
// 回退到上一个元素,即回溯
tmp.remove(tmp.size() - 1);
}
}
}