目录
问题描述:
实现代码与解析:
回溯:
原理思路:
问题描述:
        有效 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 ,用以表示一个 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"]
实现代码与解析:
回溯:
class Solution {
public:
    vector<string> result;//记录所有结果
    vector<string> path;//记录ip每一段
    //判断切割出的字符串是否合法
    bool isValid(string s)
    {
        //开头不为0且非单个字符
        if(s[0]=='0'&&s.size()!=1)
        {
            return false;
        }
        int num=0;
        //不在0~255之间
        for(int i=0;i<s.size();i++)
        {
            if(s[i]<'0'||s[i]>'9')
            {
                return false;
            }
            num=num*10+(s[i]-'0');
            if(num>255)
            {
                return false;
            }
        }
        return true;        
    }
    //回溯法
    void backtracking(string s,int startIndex)
    {
        //已经找到了4个片段
        if(path.size()==4)
        {
            //未遍历所有字符,不符合条件,返回
            if(startIndex!=s.size()) return;
            //接收结果
            result.push_back(path[0] + '.' + path[1] + '.' + path[2] + '.' + path[3]);
            return;
        }
        for(int i=startIndex;i<startIndex+3&&i<s.size();i++)//最多取3个数,且不超过字符串大小
        {
            string str=s.substr(startIndex,i-startIndex+1);//截取的片段,左开右闭
            //判断是否合法,若合法
            if(isValid(str))
            {
                path.push_back(str);//处理
                backtracking(s,i+1);//递归
                path.pop_back();//回溯
            }
            else break;
        }
        return;
    }
    vector<string> restoreIpAddresses(string s) 
    {
        backtracking(s,0);
        return result;
    }
};原理思路:
其实还是切割问题,与上一题Leetcode:131. 分割回文串(C++)_Cosmoshhhyyy的博客-CSDN博客相同只不过是把切割片段换成了"."分割而已。
1、首先要写一个判断片段是否符合条件的函数,第一个字符不能为零且整个片段表示的数大小不超过255,也不能出现非法字符。这里可以不用判断字符个数是否大于3个,我们在循环的时候控制不要超过就可以了,还能达到剪枝的效果。
 //判断切割出的字符串是否合法
bool isValid(string s)
{
    //开头不为0且非单个字符
    if(s[0]=='0'&&s.size()!=1)
    {
        return false;
    }
    int num=0;
    //不在0~255之间
    for(int i=0;i<s.size();i++)
    {
        if(s[i]<'0'||s[i]>'9')
        {
            return false;
        }
        num=num*10+(s[i]-'0');
        if(num>255)
        {
            return false;
        }
    }
    return true;        
}
2、然后写递归函数,终止条件就是已经切好了4个片段,若4个片段把所有字符都切了就将此结果按格式放入result数组中后返回,反之则直接返回。
//已经找到了4个片段
if(path.size()==4)
{
    //未遍历所有字符,不符合条件,返回
    if(startIndex!=s.size()) return;
    //接收结果
    result.push_back(path[0] + '.' + path[1] + '.' + path[2] + '.' + path[3]);
    return;
}3、最后就是递归逻辑,循环控制最多取三个且不超过字符串大小,然后截取字符串,判断是否合法,不合法就直接break此层循环,因为这次循环截取的不合法,则后面截取的一定也不合法,若合法就开始递归和回溯流程,和其他回溯题相同
for(int i=startIndex;i<startIndex+3&&i<s.size();i++)//最多取3个数,且不超过字符串大小
{
    string str=s.substr(startIndex,i-startIndex+1);//截取的片段,左开右闭
    //判断是否合法,若合法
    if(isValid(str))
    {
        path.push_back(str);//处理
        backtracking(s,i+1);//递归
        path.pop_back();//回溯
    }
}同样给大家一个流程图,方便大家理解。

地方有点小,画的比较乱,大家觉得乱的话可以忽略此图。最后一个点其实是没有的,只是为了画的时候保持截取的统一。
这里考察的就是回溯,当然还有一种方法就是直接暴力循环是最简单的,因为这里切割的片段数是有限制的,所以我们知道需要写几个循环就可以直接暴力,大家可以试试。



















