代码随想录Day19:回溯算法2

1.216组合总和三

思路:首先来说想到回溯算法可以解决组合问题,所以首先想到的就是一个回溯算法,按照回溯三部曲进行操作。其次看到里面的只能使用0-9和每个只能使用一次,所以可以对其进行剪枝操作减少对应的工作量。即确定当前到9的数的个数总和是否满足条件。

剪枝:就是根据自己的一些提前的预处理,确定哪些一定是不能满足的条件,从而减少相应的一个工作量。

class Solution {
public:
    void backtracking(vector<vector<int>>& result,vector<int>& path,int k,int n,int startIndex,int sum){
        if(sum == n){
            if(path.size() == k){
                result.push_back(path);
                return;
            }
            return;
        }
        if(sum>n){
            return;
        }
        for(int i = startIndex;i<=n&&i<=9-(k-path.size())+1;i++){//规定了范围,而且每个数只能使用一次
            path.push_back(i);
            sum += i;
            backtracking(result,path,k,n,i+1,sum);
            sum -= i;
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        vector<vector<int>> result;
        vector<int> path;
        backtracking(result,path,k,n,1,0);
        return result;
    }
};

2.17电话号码的字母组合

组合问题:使用回溯算法来进行解决。其次是一个用一个const string的数组做一个匹配。根据当前的值来确定这个的字符,然后进行相应的一个操作。终止条件:就是确定长度相等添加。其中比较难想到的可能就是一个创建对应的数组和确定对应的字符串。

class Solution {
public:
    const string callnum[8] = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    void backtracing(vector<string>& result,string& path,string digits,int startIndex){
        if(path.size() == digits.size()){
            result.push_back(path);
            return;
        }
        int digit = digits[startIndex]-'2';//确定对应的数
        string letter = callnum[digit];
        for(int i = 0;i<letter.size();i++){
            path.push_back(letter[i]);
            backtracing(result,path,digits,startIndex+1);
            path.pop_back();
        }
        return;
    }
    vector<string> letterCombinations(string digits) {
        vector<string> result;
        string path;
        if(digits.size()==0)return result;//这里要把这种情况给单独提出来,因为如果不提出来的话,返回的是一个[""]而不是[]
        backtracing(result,path,digits,0);
        return result;
    }
};

3.39组合总和

这个整体来说就是可以参考组合总和三。不过需要考虑的是这个地方的数可以无限重复,所以在这个地方我们输入的startIndex是i而不是组合总和的i+1。从而确定其可以无限重复。

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

4.40组合总和二

首先确定要使用回溯算法,然后在这个里面我们首先要对candidate进行一个排序,这样可以保证数组是一个递增的,方便后序的操作。这个地方回溯算法的难点在于如何跳过重复的,即剪枝。比如说我们要求和为6,此时的数组为1 1 1 5。我们如何将后面的那两个给去除呢。第一种方法是使用set,但是太繁琐了,操作完成之后还得复制一份给新的相对来说不好,而且这样就是一个暴力的递归,花费的时间也会比较多。所以我们使用第二种方法。

难点:使用used的辅助数组,这个辅助数组可以帮助我们确定前一个数是否被使用过了,如果使用过,且当前值和前一个数相等,那么就可以直接跳过这个了。

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

这类组合问题,基本上就是result,path,startindex作为最基础的输入参数,还有一些就需要根据实际的来进行改进了。

  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值