LeetCode 「中等」93.复原 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 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
示例
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
输入:s = "0000"
输出:["0.0.0.0"]
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
解答
- 定义有效 IP 段的条件:
- 每个段必须是一个介于 0 和 255 之间的整数
- 每个段不能以 0 开头,除非是单个 0
- 回溯法
- 使用递归函数
backtrack,尝试将字符串分割成 1 到 3 位的数字 - 如果当前路径已经包含 4 个段,并且剩余字符串为空,则说明找到了一个有效的 IP 地址
- 如果当前路径包含 4 个段,但剩余路字符串不为空,则说明当前路径无效,直接返回
- 如果当前路径少于 4 个段,尝试将剩余字符串的前 1 到 3 位作为新的段,并递归处理剩余部分
- 剪枝:
- 如果当前段不满足条件(如大于 255 或以 0 开头),直接跳过
- 如果剩余字符串长度大于长形成剩余段的最大可能度,直接跳过
Code
/**
* @param {string} s
* @return {string[]}
*/
var restoreIpAddresses = function(s) {
const ans = [];
const backtrack = (path, remaining) => {
// 如果路径长度为 4 且剩余字符串为空,说明找到了一个有效解
if (path.length === 4 && remaining.length === 0) {
ans.push(path.join('.'));
return;
}
// 剩余段数
const remainingSegments = 4 - path.length;
// 剩余字符串的最大长度(每段最多 3 位)
const maxLength = remainingSegments * 3;
// 如果剩余字符串长度超过最大长度,直接跳过
if (remaining.length > maxLength) return;
// 尝试将剩余字符串分割成 1-3 位的数字
for (let i = 1; i <= Math.min(3, remaining.length); ++i) {
const segment = remaining.slice(0, i);
// 判断当前段是否有效
if (isValid(segment)) {
path.push(segment); // 选择当前段
backtrack(path, remaining.slice(i)); // 递归处理剩余部分
path.pop(); // 撤销选择
}
}
};
// 判断一个 IP 段是否有效
const isValid = (segment) => {
// 有效条件:
// 1. 不以 0 开头(除非是单个 0)
// 2. 数字范围在 0 - 255
return (
(segment.length === 1 || !segment.startsWith('0')) &&
+segment >= 0 &&
+segment <= 255
);
};
backtrack([], s);
return ans;
};
