力扣第93题 复原IP地址 c++ 回溯

题目

93. 复原 IP 地址

中等

相关标签

字符串   回溯

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245""192.168.1.312" 和 "[email protected]" 是 无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

示例 1:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:

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

示例 3:

输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 1 <= s.length <= 20
  • s 仅由数字组成

题目解释

  • 题目要求给定一个只包含数字的字符串,将其分割成 IPv4 地址的形式。要求返回所有可能的有效 IPv4 地址。
  • IPv4 地址由4个用点分隔的数字组成,每个数字的取值范围是0到255。例如,字符串"25525511135"可以分割成"255.255.11.135"或"255.255.111.35"两种 IPv4 地址。
  • 一个只包含数字的字符串 s,通过在 s 中插入 '.' 来形成有效的 IP 地址。有效的 IP 地址由四个整数组成,每个整数位于 0 到 255 之间,且不能含有前导 0。
  • 我们需要找出所有可能的有效 IP 地址,并按任意顺序返回结果。

思路和解题方法

  1. 将原始字符串按照一定规则(插入逗点)分割成四个子字符串。
  2. 判断每个子字符串是否是合法的 IP 地址段。
  3. 如果四个子字符串都合法,则将它们拼接起来并添加到结果集中。

具体实现中,backtracking 函数通过遍历字符串的每个位置,在合适的位置插入逗点,并判断该分割是否合法。如果达到了分割成四个子字符串的条件,则判断最后一个子字符串是否合法,如果是,则将结果添加到结果集中。

isValid 函数用于判断一个子字符串是否合法,主要根据以下几个条件进行判断:

  • 如果子字符串长度大于1且以0开头,则不合法。
  • 如果子字符串包含非数字字符,则不合法。
  • 将子字符串转换为整数,并判断是否大于 255。

最后,在 restoreIpAddresses 函数中,首先进行剪枝操作,判断给定字符串的长度是否在合法范围内(4 到 12 之间),如果不满足,则直接返回结果。然后调用 backtracking 函数开始回溯过程,并返回最终结果。

复杂度

        时间复杂度:

                O(3^4)

时间复杂度: O(3^4),IP地址最多包含4个数字,每个数字最多有3种可能的分割方式,则搜索树的最大深度为4,每个节点最多有3个子节点。

        空间复杂度

                O(n)

空间复杂度: O(n)

c++ 代码

class Solution {
private:
    vector result; // 记录结果
    
    // startIndex: 搜索的起始位置,pointNum: 添加逗点的数量
    void backtracking(string& s, int startIndex, int pointNum) {
        if (pointNum == 3) { // 逗点数量为3时,分隔结束
            // 判断第四段子字符串是否合法,如果合法就放进result中
            if (isValid(s, startIndex, s.size() - 1)) {
                result.push_back(s);
            }
            return;
        }
        
        for (int i = startIndex; i < s.size(); i++) {
            if (isValid(s, startIndex, i)) { // 判断 [startIndex, i] 这个区间的子串是否合法
                s.insert(s.begin() + i + 1, '.'); // 在 i 的后面插入一个逗点
                pointNum++;
                
                backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为 i+2
                pointNum--; // 回溯
                s.erase(s.begin() + i + 1); // 回溯删掉逗点
            } else {
                break; // 不合法,直接结束本层循环
            }
        }
    }
    
    // 判断字符串 s 在左闭右闭区间 [start, end] 所组成的数字是否合法
    bool isValid(const string& s, int start, int end) {
        if (start > end) {
            return false;
        }
        
        if (s[start] == '0' && start != end) { // 0 开头的数字不合法
            return false;
        }
        
        int num = 0;
        for (int i = start; i <= end; i++) {
            if (s[i] > '9' || s[i] < '0') { // 遇到非数字字符不合法
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if (num > 255) { // 如果大于 255,则不合法
                return false;
            }
        }
        return true;
    }
    
public:
    vector restoreIpAddresses(string s) {
        result.clear();
        if (s.size() < 4 || s.size() > 12) {
            return result; // 算是剪枝了,如果字符串长度不在合法范围内,直接返回结果
        }
        backtracking(s, 0, 0);
        return result;
    }
};

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

你可能感兴趣的:(leetcode,回溯,数据结构,算法,leetcode,c++,回溯)