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至多从这个位置开始遍历

剪枝过程图如下:

LeetCode216.组合总和lll的更多相关文章

  1. [Swift]LeetCode216. 组合总和 III | Combination Sum III

    Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...

  2. 216. 组合总和 III

    216. 组合总和 III 题意 找出所有相加之和为 n 的 k 个数的组合.组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字. 说明: 所有数字都是正整数. 解集不能包含重复的 ...

  3. LeetCode 中级 - 组合总和II(105)

    给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在每个组合中只能使用一次. ...

  4. Leetcode 377.组合总和IV

    组合总和IV 给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数. 示例: nums = [1, 2, 3] target = 4 所有可能的组合为: (1, 1, 1, ...

  5. Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III)

    Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III) 同类题目: Leetcode之回溯法专题-39. 组合总数(Combination Sum) Lee ...

  6. Leetcode之回溯法专题-40. 组合总和 II(Combination Sum II)

    Leetcode之回溯法专题-40. 组合总和 II(Combination Sum II) 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使 ...

  7. 40组合总和II

    题目:给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合.candidates 中的每个数字在每个组合中只能使用一 ...

  8. [LeetCode] 39. 组合总和

    题目链接 : https://leetcode-cn.com/problems/combination-sum/ 题目描述: 给定一个无重复元素的数组 candidates 和一个目标数 target ...

  9. LeetCode刷题笔记-回溯法-组合总和问题

    题目描述: <组合总和问题>给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. cand ...

  10. Java实现 LeetCode 377 组合总和 Ⅳ

    377. 组合总和 Ⅳ 给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数. 示例: nums = [1, 2, 3] target = 4 所有可能的组合为: (1, 1 ...

随机推荐

  1. 海量数据处理利器 Roaring BitMap 原理介绍

    作者:来自 vivo 互联网服务器团队- Zheng Rui 本文结合个人理解梳理了BitMap及Roaring BitMap的原理及使用,分别主要介绍了Roaring BitMap的存储方式及三种c ...

  2. 记一次 Edge 及谷歌 Chrome 浏览器兼容性冲突的解决

    目录 记一次 Edge 及谷歌 Chrome 浏览器兼容性冲突的解决 浏览器兼容性冲突症状 解决方法 1. 把本机和远程的 8235 和 8237 端口屏蔽,包括 TCP 和 UDP 端口 2. 在 ...

  3. 认识.NET 日志系统

    认识.NET 日志系统 基本概念 日志级别:Trace<Debug<Information<Waring<Error<Critical 日志提供者(LoggingProv ...

  4. dot net core使用BackgroundService运行一个后台服务

    不管是在控制台程序还是asp.net core程序中,我们经常会有用到一个需要长时间运行的后台任务的需求.通常最直觉的方式是使用Thread实例来新建一个线程,但是这样需要自行管理线程的启动和停止. ...

  5. 震撼登场,全国产RK3588J工业核心板,让您的产品更具特色!八核2.4GHz!

    RK3588J全国产工业核心板10月正式出售如需预定,请与创龙科技联系. 更多详情,请登录创龙科技天猫旗舰店. 瑞芯微RK3568J.RK3588J技术交流QQ群:567208221,欢迎加入!

  6. Apache Kyuubi 在B站大数据场景下的应用实践

    01 背景介绍 近几年随着B站业务高速发展,数据量不断增加,离线计算集群规模从最初的两百台发展到目前近万台,从单机房发展到多机房架构.在离线计算引擎上目前我们主要使用Spark.Presto.Hive ...

  7. TypeScript 学习笔记 — 接口的使用(六)

    目录 一.函数接口参数 二.函数类型接口 三.函数混合类型 四.对象接口(最常用) 确定属性 可选属性 任意属性 只读属性 可索引接口 索引访问符 类接口 接口继承 构造函数类型 type 和 int ...

  8. 玄机-第二章日志分析-mysql应急响应

    目录 前言 简介 应急开始 准备工作 日志分析 步骤 1 步骤 2 步骤 3 步骤 4 总结 补充mysql中的/var/log/mysql/erro.log 记录上传文件信息的原因 前言 这里应急需 ...

  9. DuiLib的编译

    Duilib编译需要注意两点: 加入预处理器:WIN32;_DEBUG;_WINDOWS;UILIB_STATIC; 到这一步还是报错,报错的是DuiString  +=  这一行报错,还有Util这 ...

  10. java面试一日一题:mysql的索引下推了解吗

    问题:请问你了解索引下推吗 分析:该问题主要考察对mysql优化方面的理解 回答要点: 主要从以下几点去考虑, 1.mysql中索引的概念? 2.索引下推的理解及意义? 在面试过程中问到mysql,必 ...