【LeetCode-回溯】复原IP地址

题目描述

给定一个只包含数字的字符串,复原它并返回所有可能的 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 = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

输入:s = "0000"
输出:["0.0.0.0"]

输入:s = "1111"
输出:["1.1.1.1"]

题目链接: https://leetcode-cn.com/problems/restore-ip-addresses/

思路

使用回溯来做。使用一个数组 curAns 来保存输入的字符串被切分的子串。如果 curAns.size()==4,则说明我们找到了一个答案,然后将数组 curAns 中的子串使用.连接起来即可。

还有一个需要注意的地方就是剪枝,使用以下三种方法就可以在运行时间上超过 100% 的结果:

  • 如果当前子串 ss 长度大于 1,且 ss[0]=='0',则返回。例如,ss=="021";
  • 如果当前子串 ss 长度大于 1,且 ss 对应的数字大于 255,则返回。例如,ss=="266";
  • 如果当前结果 curAns 的长度大于 4,则返回。因为 ip 地址只有 4 段,curAns 长度大于 4,说明不是一个正确的切割。

代码如下:

class Solution {
public:
    vector<string> restoreIpAddresses(string s) {
        if(s.empty() || s.size()<4 || s.size()>12) return {};

        vector<string> curAns;
        vector<string> ans;
        dfs(s, 0, curAns, ans);
        return ans;
    }

    void dfs(string& s, int start, vector<string> curAns, vector<string>& ans){
        if(start>=s.size() && curAns.size()==4){
            string temp = "";
            for(int i=0; i<curAns.size(); i++){
                if(i==0) temp += curAns[i];
                else temp += "." + curAns[i];
            }
            ans.push_back(temp);
            return;
        }

        for(int i=start; i<s.size(); i++){
            string ss = s.substr(start, i-start+1);
            if(ss.size()>1 && ss[0]=='0') return;    // 剪枝 1
            if(ss.size()>1 && stoi(ss)>255) return;  // 剪枝 2
            curAns.push_back(ss);
            if(curAns.size()>4) return;              // 剪枝 3
            dfs(s, i+1, curAns, ans);
            curAns.pop_back();
        }
    }
};

使用一个数组来保存切割的子串,在符合条件时,将数组中的子串用.连接放进答案中是一个很好的想法,能简化代码的写法。这个想法来自这篇题解

参考

https://leetcode-cn.com/problems/combinations/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-ma-/

原文地址:https://www.cnblogs.com/flix/p/13572232.html