【算法28天:Day28】第七章回溯算法 LeetCode 复原IP地址(93)

85 阅读1分钟

题目一:

image.png

解法一:(回溯)

解题思路:其实只要意识到这是切割问题,切割问题就可以使用回溯搜索法把所有可能性搜出来

回溯三部曲

  • 递归参数

131.分割回文串 (opens new window)中我们就提到切割问题类似组合问题。

startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。

本题我们还需要一个变量pointNum,记录添加逗点的数量。

let result;// 记录结果
// startIndex: 搜索的起始位置,pointNum:添加逗点的数量
const backtracking = function(s, startIndex, pointNum) 
  • 递归终止条件

终止条件和131.分割回文串 (opens new window)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。

pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。

然后验证一下第四段是否合法,如果合法就加入到结果集里.

  • 单层搜索的逻辑

131.分割回文串 (opens new window)中已经讲过在循环遍历中如何截取子串。

for (int i = startIndex; i < s.length; i++)循环中 [startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。

如果合法就在字符串后面加上符号.表示已经分割。

如果不合法就结束本层循环,如图中剪掉的分支:

93.复原IP地址

然后就是递归和回溯的过程:

递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符.),同时记录分割符的数量pointNum 要 +1。

回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要-1。

判断子串是否合法

最后就是在写一个判断段位是否是有效段位了。

主要考虑到如下三点:

  • 段位以0为开头的数字不合法
  • 段位里有非正整数字符不合法
  • 段位如果大于255了不合法

代码随想录中代码:

var restoreIpAddresses = function(s) {
    const res = [], path = [];
    backtracking(0)
    return res;
    function backtracking(startIndex) {
        console.log('path', path)
        const len = path.length;
        if(len > 4) return;
        if(len === 4 && startIndex === s.length) {
            res.push(path.join("."));
            return;
        }
        for(let i = startIndex; i < s.length; i++) {
            const str = s.slice(startIndex, i + 1);
            if(str.length > 3 || +str > 255) break; // 若当前被截取的子串大于255或者大于三位数,直接结束本层循环
            if(str.length > 1 && str[0] === "0") break; // 若数字是0开头,不合法
            path.push(str);
            backtracking(i + 1);
            path.pop()
        }
    }
};