• 04. 组合总和


    1.题目链接:

    39. 组合总和

    2.解题思路:

    2.1.题目要求:

    给定一个“无重复数组candidates”和一个“目标和target” ,要求在给定 数组candidates 的范围内,输出和等于 目标和target 的组合,此组合元素可重复。

    示例 1: 输入:candidates = [2,3,6,7], target = 7, 所求解集为: [ [7], [2,2,3] ]

    2.2.思路:

    模拟成一个n叉树,终止条件 变成 搜索的和等于目标和

     

    2.3.回溯三部曲:

    2.3.1.确定回溯函数参数

    定义两个全局变量,一个 一维数组path 暂时存储搜集的结果,一个 二维数组result 存储最终结果集

    参数除了默认的 数组candidates 和 目标和target ,还有用于记录搜集递归过程值的sum,还有一个startIndex?感觉用不上这玩意,待会试试看

    1. vectorint>> result;
    2. vector<int> path;
    3. void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {

     

    2.3.2.确定终止条件

    当 搜集数字的总和sum 等于 目标和target 的时候,可以记录并返回了

    同时因为没有层数要求,会不断递归寻找合适的值,所以需要一个条件来限制层数,也就是当总和sum已经大于目标和target的时候。

    1. if (sum > target) return;
    2. if (sum == target) {
    3. result.push_back(path);
    4. return;
    5. }

     

    2.3.3.确定单层遍历逻辑

    这里递归到下一层搜索不用像之前那样+1,因为题目说,组合可以重复。

    1. for (int i = startIndex; i < candidates.size(); i++) {
    2. sum += candidates[i];
    3. path.push_back(candidates[i]);
    4. backtracking(candidates, target, sum, i); // 不用i+1了,表示可以重复读取当前的数
    5. sum -= candidates[i];
    6. path.pop_back();
    7. }

     

    2.4.总代码:

    1. class Solution {
    2. private:
    3. vectorint>> result;
    4. vector<int> path;
    5. void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {
    6. if (sum > target) {
    7. return;
    8. }
    9. if (sum == target) {
    10. result.push_back(path);
    11. return;
    12. }
    13. for (int i = startIndex; i < candidates.size(); i++) {
    14. sum += candidates[i];
    15. path.push_back(candidates[i]);
    16. backtracking(candidates, target, sum, i); // 不用i+1了,表示可以重复读取当前的数
    17. sum -= candidates[i];
    18. path.pop_back();
    19. }
    20. }
    21. public:
    22. vectorint>> combinationSum(vector<int>& candidates, int target) {
    23. result.clear();
    24. path.clear();
    25. backtracking(candidates, target, 0, 0);
    26. return result;
    27. }
    28. };

     

    2.5.剪枝优化

     如图所示,当sum > target的时候就会返回,如果可以提前预测下一层的sum 会不会大于 target,如果大于就跳过,这样就可以省去一层遍历了,剪枝成功。

    剪枝可以在for循环范围作改动,在范围那提前预测,加上  && sum + candidates[i] <= target ,在预测下一层sum不大于target的前提继续递归。

    注意,剪枝前记得,要先排序,不排序 sum + candidates[i] <= target的代码预测可能不准,因为,如果一开始下一层就遇见很大的数的话(超过target),那这一整层都会被剪掉,这样就缺少了很多组合。

     for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++)

     

    剪枝代码如下:

    1. class Solution {
    2. private:
    3. vectorint>> result;
    4. vector<int> path;
    5. void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {
    6. if (sum == target) {
    7. result.push_back(path);
    8. return;
    9. }
    10. // 如果 sum + candidates[i] > target 就终止遍历
    11. for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
    12. sum += candidates[i];
    13. path.push_back(candidates[i]);
    14. backtracking(candidates, target, sum, i);
    15. sum -= candidates[i];
    16. path.pop_back();
    17. }
    18. }
    19. public:
    20. vectorint>> combinationSum(vector<int>& candidates, int target) {
    21. result.clear();
    22. path.clear();
    23. sort(candidates.begin(), candidates.end()); // 需要排序
    24. backtracking(candidates, target, 0, 0);
    25. return result;
    26. }
    27. };

     

    3.遇见的问题:

    3.1starIndex的作用?

    写了一遍,一开始感觉是固定每一层递归从0开始。

    但下一层递归传的不是starIndex,是 i ?。这是什么原理?

    按理来说反正下一层递归 i 默认都是被index赋值等于 0 的,也就是传入啥都可以,不影响

    但是这样却报错了,要换成 i 才给过,回忆下过程每一层都是从 0 开始,传入的 i 在我看来根本没意义啊,他起到的作用是什么 ?

    哦哦,回看了下之前的 001.组合的代码,那里是 i+1,代表每一次取过的数不再取,哪里的index是用来定位的,

    用这里的i类比的话,意思大概就是可以取,取过的数,递归下一层从 i 而不是从0开始,是因为之前的数已经取过了的意思吧

     比如画圈这里,2,5已经用过,只能从3取,哦哦,下一层递归的目的是为了避免组合重复出现,第一层已经确认大部分的组合了,后面只是补漏,从 i 取可以避免元素重复。

    4.记录:

    果然之前的理解还是有很多漏洞,现在补上了(大概..)

    与之前题目的不同点:

    • 组合没有数量要求
    • 元素可无限重复选取
  • 相关阅读:
    java4.23学习总结
    es重启临时关闭自动分片
    『GitHub Actions』部署静态博客指南
    SpringBoot整合mybatis
    商标的跨类别保护
    解决:AttributeError: ‘WebDriver‘ object has no attribute ‘find_element_by_xpath‘
    嵌入式C开发关键字的应用技巧
    零信任沙盒
    JavaFx之使用高版本JDK(二十八)
    海思3559万能平台搭建:在截获的YUV图像上画框
  • 原文地址:https://blog.csdn.net/qq_70280303/article/details/128091043