题:
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
示例:
输入: "25525511135"
输出: ["255.255.11.135", "255.255.111.35"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/restore-ip-addresses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解:
此题又是一道典型的「回溯」类题目。
「回溯」的「循环不变式」不够明显:通过递归枚举所有可能。回退时,恢复现场;终止时,更新答案集。
对于这道具体的题目,要通过耐心分析找到一个恰当的递归枚举方式,然后就是筛选出每一次递归枚举时的所有有效选择。
此题好玩的地方在于这个判断有效选择的条件比较繁琐,此时适合抽出布尔变量。
var restoreIpAddresses = function(s) {
const ans = []
const choices = []
const l = s.length
// 辅助函数
function parseIP() {
const IP = choices.join('')
if (IP.split('.').every(e => parseInt(e) < 256)) ans.push(IP)
}
function backtrack(i = 0, pointCount = 0, last = -1, sliceLength = 0) {
// 递归终止,尝试添加有效 IP
if (pointCount === 3 && i === l) parseIP()
// 越界直接返回,或许可以不需要,但放在这里更安全
else if (pointCount > 3 || i > l) return
// 回溯:递归 + 回退前清理现场
else {
// 一共两种可能
const canPushNumber = (sliceLength > 0 && sliceLength < 3 && choices[last + 1 - sliceLength] != '0') || sliceLength === 0
const canPushPoint = sliceLength > 0 && sliceLength <= 3
// 分别对两种可能进行操作
if (canPushNumber) {
choices[last + 1] = s[i]
backtrack(i + 1, pointCount, last + 1, sliceLength + 1)
}
if (canPushPoint) {
choices[last + 1] = '.'
backtrack(i, pointCount + 1, last + 1, 0)
}
// 回退之前清理现场
choices.length = last + 1
}
}
backtrack()
return ans
};