开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
93. 复原IP地址
题目分析
题目给出了一个只包含数字的字符串,用来表示一个IP地址,要求返回所有可能的有效IP地址。
有效 IP 地址 正好由四个整数(每个整数位于
0到255之间组成,且不能含有前导0),整数之间用'.'分隔。
解题
这道题与分割问题类似,都可以使用模拟成树状结构的回溯算法解决。
仍然是回溯三部曲:
- 递归函数的参数
递归函数的参数为包含已经遍历的字符串的数组以及遍历字符串的开始位置。我们需要通过开始位置这个变量来防止重复遍历。
- 回溯函数终止条件
当存放遍历过字符串的数组的长度为4(因为每次我们存放的是符合要求的一段字符串),并且耗尽所有字符时,可以将结果放入结果数组中,并且返回。
if(subRes.length === 4 && start === s.length) {
res.push(subRes.join("."))
return
}
还有一种情况是数组长度为4,但是并没有将给定字符串遍历完。这时候就不用继续进行,可以直接返回。
if(subRes.length === 4 && start < s.length) return
- 单层搜索的过程
因为有效的IP地址,每一段最多有三个数字。所以我们通过for循环遍历1~3这三种结果。同时需要判断结果是否有效,有三种不正确的切割方式:
- 开始位置加上要切得长度超过了给出字符串的长度
- 如果要切的长度大于一并且第1个元素为0
- 要切的长度为3,并且大于255
我们需要在循环中判断,如果合理那么进行递归,这里要注意的是传入的开始位置为本次的开始位置加上切割的长度。
for(let len = 1;len <= 3;len++) {
if(start + len - 1 >= s.length) return
if(len !== 1 && s[start] === '0') return
const str = s.substring(start,start + len)
if(len === 3 && +str > 255) return
subRes.push(str)
dfs(subRes,start + len)
subRes.pop()
}
总结
这道题对于我来说还是比较难以理解的,在leetcode中看到一个很好的题解,通过题解中的图解,我逐步解决了这道题。93. 复原 IP 地址 - 力扣(Leetcode),大家可以去看看。
其中我看到一份关于回溯的讲义,感觉非常有帮助。
Backtracking is a form of recursion. The usual scenario is that you are faced with a number of options, and you must choose one of these. After you make your choice you will get a new set of options; just what set of options you get depends on what choice you made. This procedure is repeated over and over until you reach a final state. If you made a good sequence of choices, your final state is a goal state; if you didn't, it isn't. 粗略翻译:回溯是递归的一种形式,通常情况是,你面临一些选项,你必须选择其中一个。在你做出选择后,你又会得到一组新的选择,即你所得到的选项取决于你所做的选择。这种步骤不断重复,直到你到达最终状态,如果你一直做出对的选择,最后的状态就是目标状态。如果你没有,它就不是。