leetcode 93. 复原IP地址 思考分析

147 阅读2分钟

题目

给定一个只包含数字的字符串,复原它并返回所有可能的 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 地址。
在这里插入图片描述
在这里插入图片描述

思考

这一题和leetcode 131. 分割回文串 思考分析很像,都属于利用回溯法分割字符串,所以解法上具有一定相似性。
回溯终止条件
如果逗号已经插入了3次了,观察最后一次插入往后的位置,观察剩下来的字符串能否构成合法字符串。
如果能构成,那么将s装入结果;
如果不能构成,回溯到上一个阶段。

//如果逗号数量为3,判断第四个子区间是否合法,如果合法就放入结果中
if(point_nums==3)
{
    if(isValid(s,startindex,s.size()-1))
    {
        result.push_back(s);
    }
    return;
}

回溯逻辑
1、这里利用逗号来进行分割,在原string上进行操作。如果startindex~i之间的字符串合法的话,我们就在i后面插入一个逗号。
然后对逗号后面的字符串进行回溯遍历。不满足的回溯组合将把逗号消除,完成回撤。

for(int i=startindex;i<s.size();i++)
{
   //子串区间:[startindex,i]
   if(isValid(s,startindex,i))     //判断子串区间的子串是否合法
   {
       s.insert(s.begin()+i+1,'.'); //在i后面插入一个逗号
       point_nums++;
       backtracking(s,i+2);        //切割过的字符不能再次被切割,插入逗号之后下一个子串的起始位置发生往后移动1
       //回溯撤销
       point_nums--;
       s.erase(s.begin()+i+1);     //回溯删除逗号
   }
   //不合法的子串直接结束本层循环,只要一个子串不合法,结果就是不合法的
   else break;
}

2、考察字符串是否合法:

//判断字符串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) return false;
    }
    return true;
}

完整代码

class Solution {
public:
    vector<string> result;
    int point_nums=0;
    //判断字符串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) return false;
        }
        return true;
    }
    //这里直接对s进行修改
    void backtracking(string& s,int startindex)
    {
        //如果逗号数量为3,判断第四个子区间是否合法,如果合法就放入结果中
        if(point_nums==3)
        {
            if(isValid(s,startindex,s.size()-1))
            {
                result.push_back(s);
            }
            return;
        }
        for(int i=startindex;i<s.size();i++)
        {
            //子串区间:[startindex,i]
            if(isValid(s,startindex,i))     //判断子串区间的子串是否合法
            {
                s.insert(s.begin()+i+1,'.'); //在i后面插入一个逗号
                point_nums++;
                backtracking(s,i+2);        //切割过的字符不能再次被切割,插入逗号之后下一个子串的起始位置发生往后移动1
                //回溯撤销
                point_nums--;
                s.erase(s.begin()+i+1);     //回溯删除逗号
            }
            //不合法的子串直接结束本层循环,只要一个子串不合法,结果就是不合法的
            else break;
        }
    }
    vector<string> restoreIpAddresses(string s) {
        result.clear();
        point_nums=0;
        backtracking(s,0);
        return result;
    }
};