Leetcode:93. 复原 IP 地址(C++)

目录

问题描述:

实现代码与解析:

回溯:

原理思路:


问题描述:

        有效 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();//回溯
    }
}

        同样给大家一个流程图,方便大家理解。

         地方有点小,画的比较乱,大家觉得乱的话可以忽略此图。最后一个点其实是没有的,只是为了画的时候保持截取的统一。

        这里考察的就是回溯,当然还有一种方法就是直接暴力循环是最简单的,因为这里切割的片段数是有限制的,所以我们知道需要写几个循环就可以直接暴力,大家可以试试。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cosmoshhhyyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值