代码随想录训练营Day28 第七章 回溯算法 ● 93.复原IP地址 ● 78.子集 ● 90.子集II

题目链接:93. 复原 IP 地址 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址

这道题在理解“分割”后,就比较简单了,与分割回文串不同,这道题限制了分割的次数,只允许分割成四段,也就是3个'.',所以我们就可以通过一个int参数pointnum记录记录'.'的个数,终止条件就是pointnum==3.另外还需要判定最后一段是否是有效字符串,所以终止条件的代码就出来:

if(pointnum==3&&isvalid(s,index,s.size()-1)==true) 
        result.push_back(s);

除此之外,就是需要自定义一个函数,来确定是否是有效字符串,需要满足几个条件。

1.不可以有前导0

if(s[start]=='0'&&start!=end) return false;//不含前导0

2.每一段字符串都不能大于255

3.不可以出现0-9以外的字符

for(int i=start;i<=end;i++){
            if(s[i]<'0'||s[i]>'9') return false;
            num=num*10+(s[i]-'0');
            if(num>255) return false;
        }

4.每一段字符串都不能为空

if(start>end) return false;

自定义函数代码如下:

bool isvalid(string& s,int start,int end){
        if(start>end) return false;//防止出现最后一段没有字符的情况
        if(s[start]=='0'&&start!=end) return false;//不含前导0
        int num=0; 
        for(int i=start;i<=end;i++){
            if(s[i]<'0'||s[i]>'9') return false;
            num=num*10+(s[i]-'0');
            if(num>255) return false;
        }
        return true;
    }

总代码如下:

class Solution {
public:
    vector<string> result;
    bool isvalid(string& s,int start,int end){
        if(start>end) return false;//防止出现最后一段没有字符的情况
        if(s[start]=='0'&&start!=end) return false;//不含前导0
        int num=0; 
        for(int i=start;i<=end;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 index,int pointnum)
    {
        if(pointnum==3&&isvalid(s,index,s.size()-1)==true) 
        result.push_back(s);
        for(int i=index;i<s.size();i++)
        {
            if(isvalid(s,index,i)==true)
            {
            s.insert(s.begin()+1+i,'.');
            backtracking(s,i+2,pointnum+1);//因为加了个'.',所以需要i+2
            s.erase(s.begin()+1+i);
            }else break;
        }
    }
    vector<string> restoreIpAddresses(string s) {
        backtracking(s,0,0);
        return result;
    }
};

78.子集

 题目链接:78. 子集 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:回溯算法解决子集问题,树上节点都是目标集和! | LeetCode:78.子集

这道题在我们做了这么多回溯题值后,还是比较easy的。找到所有的子集,包括空集和本身,甚至连终止条件都不需要。

只需要在每一次回溯的过程时把元素存进path,再将path存进result就好。

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>nums,int index){
        result.push_back(path);
        for(int i=index;i<nums.size();i++){
        path.push_back(nums[i]);
        backtracking(nums,i+1);
        path.pop_back();
        }
        return;
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        backtracking(nums,0);
        return result;
    }
};

90.子集II 

 

 题目链接:90. 子集 II - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:回溯算法解决子集问题,如何去重?| LeetCode:90.子集II

 这道题与上一题的区别在于这道题集合中可能包含重复元素,所以需要采用去重操作。

去重操作有三个关键点:1.对数组重新排序。 2.相同元素的只遍历一次,剩下的都跳过

3.使用bool数组used记录上一元素是否“使用过”

Day27有讲过去重的具体操作

for(int i=index;i<candidates.size()&& sum + candidates[i] <= target;i++){
            if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false){//去重
                continue;
            }
            path.push_back(candidates[i]);
            used[i]=true;
            backtracking(candidates,target,sum+candidates[i],i+1,used);
            used[i]=false;
            path.pop_back();
        }

总代码如下:

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(vector<int>& nums,int index,vector<bool>&used)
    {
        result.push_back(path);
        for(int i=index;i<nums.size();i++){
        if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false){//去重
            continue;
        }
        path.push_back(nums[i]);
        used[i]=true;
        backtracking(nums,i+1,used);
        used[i]=false;
        path.pop_back();
        }
        return;
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());//排序
        vector<bool> used(nums.size(),false);
        backtracking(nums,0,used);
        return result;
    }
};

 Day28打卡成功,耗时3.5小时,对去重操作进行巩固,并对回溯算法有了更深刻的理解,再接再厉!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值