这道题本质是在分隔字符串,需要把给定的字符串分割成四个部分,每个部分满足IP地址的条件就是正确的IP地址,分割的题用回溯解决。
这道题难点在于判断情况比普通回溯题的情况要复杂一些,比如有很多种情况让程序回溯回去,而不只是一俩个确定的不满足条件。
判断IP地址是否正确:
首先根据题目描述,一个正确的IP地址由四个IP分段组成,每个IP分段有数字大小和格式的限制,观察发现每个IP分段最多由三位数构成,最少由一位数构成,四个IP分段必须都是这个标准,由此可以得出判断IP地址是否正确的条件。
如果满足正确IP地址条件,就推入准备好的 res 结果数组。
IP分段不正确的情况:
1.如果某部分达到了三位数,且该部分数值大于255
2.某部分长度不为 1 ,但是该部分开头元素为 0
3.最后一部分IP分段达到每一种情况时,给定的字符串还没有用尽。
递归函数
我们需要一个参数 start 来表示每次从字符串的哪个位置开始进行分隔,但是每个 start 开始构建该部分IP分段都会有三种情况:
1.一位数;2.俩位数;3.三位数;
所以每次从 start 开始构建该部分IP分段的时候都要遍历三次,每一次取对应位数的IP分段,对每次取出来的IP分段都要进行判断该IP分段是否符合要求,如果符合要求就推入待定数组 path 。
处理IP分段不正确情况3的思路:
该情况下IP分段为最后一段,想要使整体符合正确IP地址的要求,最后一段IP分段肯定是要用尽给定的字符串的,怎么判断是否用尽了呢?
由于每一个IP分段都是从给定字符串的本次起始位置 与 达到该IP分段三种不同长度的某一种位置截取的,
即判断:该种最后一段IP分段位数情况之一的 起始位置 + 当前是最后IP分段哪一种长度 是否等于 给定字符串的长度,如果是的话,就证明最后一段IP分段的该种位数情况正好用尽了给定字符长度,则是正确的最后IP分段。
回溯:
每次遇到不符合要求的IP分段情况,就退回到上一个状态继续寻找。
代码如下:
var restoreIpAddresses = function (s) {
const res = [];
const backtrack = (path, start) => {
// 符合有效IP地址的总判断
if (path.length === 4 && start === s.length) {
res.push(path.join('.'));
return;
}
// 不符合最终有效IP则返回
if (path.length === 4 && start < s.length) {
return;
}
// 从每一个IP分段的起始位置开始,有三种该段情况(子段长度分别为1,2,3)
for (let len = 1; len <= 3; len++) {
// 加上本次IP分段位数的长度越界
if (start + len -1 > s.length) return;
// 该IP分段位数不为 1 但是开头为 0
if (len > 1 && s[start] == '0') return;
// IP分段位数为3时,是否超出255
let str = s.slice(start, start + len);
if (len === 3 && +str > 255) return;
// 符合IP分段情况,推入待定数组
path.push(str);
// 注意这个 start + len 用来判断最后部分的IP分段是否用尽了给定字符串
backtrack(path, start + len);
// 回溯:返回上一个状态
path.pop();
}
}
backtrack([], 0);
return res;
};