首页 > 其他分享 >LeetCode216.组合总和lll

LeetCode216.组合总和lll

时间:2024-08-14 18:27:36浏览次数:9  
标签:size int sum startindex targetSum lll path 总和 LeetCode216

4.组合总和lll(LeetCode216)

题目叙述:

找出所有相加之和为 nk 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。

示例 3:

输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。

提示:

  • 2 <= k <= 9
  • 1 <= n <= 60

思路:

1.回溯函数的参数以及返回值

  • 没有返回值

  • 我们需要startindex变量来标志着我们遍历的位置

  • 并且需要一个一维数组path来存放当前的结果,一个二维数组result来存储最终的结果集。

  • targetSum(int)目标和,也就是题目中的n。

  • k(int)就是题目中要求k个数的集合。

  • sum(int)为已经收集的元素的总和,也就是path里元素的总和。

  • startIndex(int)为下一层for循环搜索的起始位置。

代码如下:

vector<vector<int>> result;
vector<int> path;
void backtracking(int targetSum, int k, int sum, int startIndex)

2.回溯函数的结束条件

  • 当我们数组中的元素个数等于k时,就收集到了k个元素,也就是我们满足题目的条件,此时就应该返回了
  • 并且,如果此时的targetSum=sum了,就是满足我们题目要求的一个答案,我们就应该收集这个答案了。

代码如下:

if(path.size()==k){
    if(sum==targetSum) result.push_back(path);
    return;
}

3.单层递归的逻辑

  • 此处我们是选择1-9的九个数字,因此单层递归的for循环应该是≤9
for(int i=startindex;i<=9;i++)
  • 处理过程就是 path收集每次选取的元素,相当于树型结构里的边,sum来统计path里元素的总和

  • 并且,我们还需要有回溯的过程,只要加了的话,我们要回到上一层,重新选择的话,此时我们就应该减回来

代码如下:

for(int i=startindex;i<=9;i++){
    path.push_back(i);
    sum+=i;
    //此时这里是i+1,因为元素不能够重复取
    backtracking(targetSum,k,sum,i+1);
    //这里是回溯的逻辑,在之前加过的元素,如果我们要回溯到上一层再操作,就要减回来
    sum-=i;
    path.pop_back();
}
  • 其实,我们也不需要对sum做加减的操作,直接对传入的参数进行操作,这样相当于是将回溯的逻辑隐藏在了递归函数中,不推荐这种做法。
for(int i=startindex;i<=9;i++){
    path.push_back(i);
    //此时这里是i+1,因为元素不能够重复取
    backtracking(targetSum,k,sum+i,i+1);
    path.pop_back();
}

代码:

  • 我们根据上面三步的分析,不难得出代码:
class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(int targetSum, int k, int startindex, int sum) {
        if (path.size() == k) {
            if (sum == targetSum)
                result.push_back(path);
            return;
        }
        for (int i = startindex; i <= 9; i++) {
            sum += i;
            path.push_back(i);
            backtracking(targetSum, k, i + 1, sum);
            //回溯的过程
            path.pop_back();
            sum -= i;
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        //从1开始选
        backtracking(n, k, 1, 0);
        return result;
    }
};

剪枝:

  • 在这段代码中,我们可以有两个剪枝的过程。
  1. 第一就是如果我们发现当前的sum已经大于targetSum了,那么我们就没有必要就再往下进行遍历了,肯定没有符合条件的k个数相加为n。
    void backtracking(int targetSum, int k, int startindex, int sum) {
        //发现sum已经大于targetSum了,直接结束本层递归
        if(sum>targetSum) return;
        if (path.size() == k) {
            if (sum == targetSum)
                result.push_back(path);
            return;
        }
        for (int i = startindex; i <= 9; i++) {
            sum += i;
            path.push_back(i);
            backtracking(targetSum, k, i + 1, sum);
            //回溯的过程
            path.pop_back();
            sum -= i;
        }
    }
  1. 第二就是单层递归的条件,我们没有必要从startindex遍历到9,只需要遍历到9-(k-path.size())+1即可
  • 为什么只需要遍历到9-(k-path.size())+1就可以了呢?这题的逻辑其实和我们之前讲解的LeetCode77组合总和有异曲同工之妙,我们数组中的元素个数为path.size()个,我们还需要选择k-path.size()个元素
  • 又因为我们是从i开始,树的最底层,也就是递归的深度,是遍历到9结束,那么这个区间内的元素个数必须≥k-path.size()
  • 这个区间的元素个数为:9-i+1,那么9-i+1>=k-path.size(),可以推出i<=9-(k-path.size())+1,就是说i至多从这个位置开始遍历

剪枝过程图如下:

216.组合总和III1

标签:size,int,sum,startindex,targetSum,lll,path,总和,LeetCode216
From: https://www.cnblogs.com/Tomorrowland/p/18359547

相关文章

  • LeetCode 216. 组合总和 III 回溯写法详解
    216.组合总和III216.组合总和III题目来源题目分析题目难度题目标签题目限制解题思路核心算法步骤代码实现代码解读性能分析测试用例扩展讨论优化写法其他实现总结216.组合总和III题目来源216.组合总和III题目分析题目要求找出所有相加之和为n的k......
  • 在 SQL 中,怎样使用聚合函数(如 SUM、AVG、COUNT 等)来计算数据的总和、平均值和数量?
    在SQL中,可以使用聚合函数来计算数据的总和、平均值和数量。以下是一些常用的聚合函数的示例:SUM函数:计算指定列的总和。SELECTSUM(column_name)FROMtable_name;AVG函数:计算指定列的平均值。SELECTAVG(column_name)FROMtable_name;COUNT函数:计算指定列的数......
  • 代码随想录day23 || 39 组合总和,40 组合总和2,131 分割回文串
    39组合总和funccombinationSum(candidates[]int,targetint)[][]int{ //思路,组合问题考虑回溯算法,考虑到元素可能重复问题,所以,树的最大深度应该是target/min(candudates)+1 varpath=[]int{} varres=[][]int{} backtracking(target,candidates,&path,&res......
  • 算法力扣刷题记录 六十四【216.组合总和III】
    前言回溯第二篇。回顾:上一篇学了回溯的基础知识和模版;组合练习题一应用了一次模版。本文继续组合问题练习:记录六十四【216.组合总和III】。一、题目阅读找出所有相加之和为n的k个数的组合,且满足下列条件:只使用数字1到9每个数字最多使用一次返回所有可能的有效......
  • (算法)组合总和————<递归>
    1.题⽬链接:39.组合总和 2.题⽬描述:3.解法:算法思路:candidates的所有元素互不相同,因此我们在递归状态时只需要对每个元素进⾏如下判断:1.跳过,对下⼀个元素进⾏判断;2.将其添加⾄当前状态中,我们在选择添加当前元素时,之后仍可以继续选择当前元素(可以重复选择同⼀元素......
  • 代码随想录算法训练营第二十一天| 39. 组合总和, 40.组合总和II, 131.分割回文串
    今天是回溯算法学习的第二天,主要的学习内容包括:1.组合问题的重复使用2.组合问题的去重3.分割问题的处理方法。39.组合总和题目链接:39.组合总和-力扣(LeetCode)这个组合问题的特点是,集合内的元素可以重复使用。与前面组合问题的区别在于,在每一次回溯中,不是从i+1的位置开......
  • 代码随想录训练第三十二天|完全背包理论基础、LeetCode518.零钱兑换II、LeetCode377.
    文章目录完全背包理论基础完全背包总结518.零钱兑换II思路一维数组二维数组377.组合总和Ⅳ思路卡码网70.爬楼梯(进阶版)思路完全背包理论基础完全背包有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品都有无......
  • (算法)找出所有⼦集的异或总和再求和————<递归>
    1.题⽬链接:1863.找出所有⼦集的异或总和再求和 2.题⽬描述:3.解法(递归):算法思路:所有⼦集可以解释为:每个元素选择在或不在⼀个集合中(因此,⼦集有个)。本题我们需要求出所有⼦集,将它们的异或和相加。因为异或操作满⾜交换律,所以我们可以定义⼀个变量,直接记录当前状态的异......
  • 代码随想录 day 37 完全背包 | 零钱兑换 II | 组合总和 Ⅳ | 爬楼梯 (进阶)
    完全背包完全背包解题思路由于我们可以重复放入物体,那么在遍历背包重量时就必须从前往后遍历,因为这样就可以重复放入了,其余的部分和01背包相同知识点完全背包心得学会了如何解决纯完全背白零钱兑换II零钱兑换II解题思路和之前01背包求总数的思路相同,唯一的不同点在......
  • 像素值与 2D NPS 的标准差 - NPS 的总和还是平均值?
    我正在尝试根据Python中的2DNPS估计空间域中像素值的SD。我希望需要NPS值的总和除以像素总数。然而,我只能通过平均值除以像素总数来达到正确的估计。任何人都可以指出我为什么会这样吗?请参阅下面的代码示例。“SUM:“importnumpyasnpfromscipy.ff......