复原 IP 地址
难度:
标签:
题目描述
有效 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
仅由数字组成
代码结果
运行时间: 64 ms, 内存: 15 MB
/*
* 题目思路:
* 1. 使用流式API,将字符串划分成可能的IP地址片段。
* 2. 过滤出符合IP地址规范的片段组合。
* 3. 将结果收集为列表。
*/
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class RestoreIPAddressesStream {
public List<String> restoreIpAddresses(String s) {
return IntStream.range(1, s.length()).boxed()
.flatMap(i -> IntStream.range(i + 1, s.length()).boxed()
.flatMap(j -> IntStream.range(j + 1, s.length()).boxed()
.map(k -> new int[]{i, j, k})))
.map(indices -> new String[]{s.substring(0, indices[0]), s.substring(indices[0], indices[1]), s.substring(indices[1], indices[2]), s.substring(indices[2])})
.filter(parts -> isValid(parts))
.map(parts -> String.join(".", parts))
.collect(Collectors.toList());
}
private boolean isValid(String[] parts) {
return parts.length == 4 &&
IntStream.range(0, 4).allMatch(i -> isValidSegment(parts[i]));
}
private boolean isValidSegment(String segment) {
if (segment.length() > 1 && segment.startsWith("0")) return false;
int value = Integer.parseInt(segment);
return value >= 0 && value <= 255;
}
}
解释
方法:
这道题使用回溯算法来解决。基本思路是:从字符串的左侧开始,依次选取1到3个字符作为IP地址的一段,然后递归处理剩余部分。在递归过程中,如果已经选取了4段并且字符串恰好用完,则找到一个有效的IP地址。递归回溯的过程中注意两点:1. 每一段必须在0~255的范围内;2. 如果一段包含多位数字,则第一位不能为0。
时间复杂度:
O(1)
空间复杂度:
O(1)
代码细节讲解
🦆
在递归回溯过程中,为什么选择分割长度从1到3个字符,这与IP地址的哪些特性相关?
▷🦆
算法中提到,如果一段有前导零则跳过,这样做的原因是什么?是否所有包含前导零的字符串段都不可能成为有效的IP地址段?
▷🦆
在判断一个段是否大于255时,是否考虑了某些边界情况,例如字符串形式的数字超过了整型的常规处理范围?
▷🦆
递归函数中,`begin` 变量的作用具体是什么?它如何帮助处理字符串的剩余部分?
▷