• 【代码随想录算法训练Day27】LeetCode 39.组合总和、LeetCode 40.组合总和II、LeetCode 131.分割回文串


    Day27 回溯第三天

    LeetCode 39.组合总和

    和上一题比较相似,不一样的地方是元素可以重复选取了,也就是我们中间的递归不是向下一个元素递归,而是重复递归本元素,因为同一个元素可能会多次使用。

    class Solution {
    private:
        vector<vector<int>> res;
        vector<int> path;
    public:
        void dfs(vector<int>& candidates,int target,int startidx){
            if(target<0) return;
            if(target==0){
                res.push_back(path);
                return;
            }
            for(int i=startidx;i<candidates.size();i++){
                path.push_back(candidates[i]);
                target-=candidates[i];
                dfs(candidates,target,i);
                target+=candidates[i];
                path.pop_back();
            }
        }
    
        vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            dfs(candidates,target,0);
            return res;            
        }
    };
    

    LeetCode 40.组合总和II

    本体还是很有难度的,难点在于去重的思路。如何能在重复取数组的元素却又不让结果集重复。
    这里给出的方法是:用used数组保证每个元素只取一次,给整个数组排序,相同的元素只取第一个(保证不污染后面的used数组,防止影响后面的判断),然后逐个回溯递归。

    class Solution {
    public:
        vector<int> path;
        vector<vector<int>> res;
    
        void backtrack(vector<int>& candidates,int target,int sum,int startIndex,vector<bool>& used){
            if(target==sum){
                res.push_back(path);
                return;
            }
            for(int i=startIndex;i<candidates.size() && sum+candidates[i]<=target;i++){
                if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==false)
                    continue;
                sum+=candidates[i];
                path.push_back(candidates[i]);
                used[i]=true;
                backtrack(candidates,target,sum,i+1,used);
                used[i]=false;
                sum-=candidates[i];
                path.pop_back();
            }
        }
        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            vector<bool> used(candidates.size(),false);
            sort(candidates.begin(),candidates.end());
            backtrack(candidates,target,0,0,used);
            return res;
        }
    };
    

    LeetCode 131.分割回文串

    本题的难点反而不在回溯,而在如何处理子串的分割上,如何才能将字符串按不同方式分开,同时判断是否是回文串呢。
    这里给出的答案是我们每次分割时,startIndex就是分割串的分界线,[startIndex,i]就是我们要处理的子串,每次判断子串是否回文,不回文直接跳过。也就是当我们走到叶子结点时,它就一定是满足题意的字符串了。

    class Solution {
    private:
        vector<vector<string>> res;
        vector<string> path;
        bool isPalindrome(const string& s,int start,int end){
            for(int i=start,j=end;i<j;i++,j--)
                if(s[i]!=s[j])
                    return false;
            return true;
        }
    
        void backtrack(const string& s,int startIndex){
            if(startIndex>=s.size()){
                res.push_back(path);
                return;
            }
            for(int i=startIndex;i<s.size();i++){
                if(isPalindrome(s,startIndex,i)){
                    string str=s.substr(startIndex,i-startIndex+1);
                    path.push_back(str);
                }
                else continue;
                backtrack(s,i+1);
                path.pop_back();
            }
        }
    public:
        vector<vector<string>> partition(string s) {
            backtrack(s,0);
            return res;
        }
    };
    

    难点反而在理解题意了。

  • 相关阅读:
    Signoff Criteria --- ocv applied and results
    Linux高性能服务器编程 学习笔记 第七章 Linux服务器程序规范
    目标检测算法——图像分类开源数据集汇总(附下载链接)
    springboot的缓存和redis缓存,入门级别教程
    Docker CMD和ENTRYPOINT的区别
    【Java刷题进阶】基础入门篇⑥
    Linux安装MySQL
    【uni-app系列】uni-app之App打包
    人工智能导论网课笔记与实战
    torch.manual_seed(0)报错RuntimeError: CUDA error: unspecified launch failure
  • 原文地址:https://blog.csdn.net/qq_46121420/article/details/139420969