代码随想录Day22
77. 组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
输入:n = 1, k = 1
输出:[[1]]
提示:
1 <= n <= 20
1 <= k <= n
正解(回溯)
直接的解法当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。
输入:n = 100, k = 3 那么就三层for循环
如果n为100,k为50呢
此时就会发现虽然想暴力搜索,但是用for循环嵌套连暴力都写不出来
上面我们说了要解决 n为100,k为50的情况,暴力写法需要嵌套50层for循环,那么回溯法就用递归来解决嵌套层数的问题。
递归来做层叠嵌套(可以理解是开k层for循环),每一次的递归中嵌套一个for循环,那么递归就可以用于解决多层嵌套循环的问题了。
- 递归函数的返回值以及参数
在这里要定义两个全局变量,一个用来存放符合条件单一结果,一个用来存放符合条件结果的集合。
函数里一定有两个参数,既然是集合n里面取k个数,那么n和k是两个int型的参数。
然后还需要一个参数,为int型变量startIndex,这个参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 - 回溯函数终止条件
什么时候到达所谓的叶子节点了呢?
path这个数组的大小如果达到k,说明我们找到了一个子集大小为k的组合了,在图中path存的就是根节点到叶子节点的路径。 - 单层搜索的过程
回溯法的搜索过程就是一个树型结构的遍历过程,在如下图中,可以看出for循环用来横向遍历,递归的过程是纵向遍历。
for循环每次从startIndex开始遍历,然后用path保存取到的节点i。
上代码(●'◡'●)
class Solution {
private:
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = startIndex; i <= n; i++) {
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归
path.pop_back(); // 回溯,撤销处理的节点
}
}
public:
vector<vector<int>> combine(int n, int k) {
result.clear(); // 可以不写
path.clear(); // 可以不写
backtracking(n, k, 1);
return result;
}
};
组合问题是回溯法解决的经典问题,我们开始的时候给大家列举一个很形象的例子,就是n为100,k为50的话,直接想法就需要50层for循环。
从而引出了回溯法就是解决这种k层for循环嵌套的问题。
然后进一步把回溯法的搜索过程抽象为树形结构,可以直观的看出搜索的过程。
接着用回溯法三部曲,逐步分析了函数参数、终止条件和单层搜索的过程。
优化(剪枝)
来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。

正如图所示,这种优化就像是把递归树上多余的枝杈剪掉了
图中每一个节点(图中为矩形),就代表本层的一个for循环,那么每一层的for循环从第二个数开始遍历的话,都没有意义,都是无效遍历。
所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。
接下来看一下优化过程如下:
- 已经选择的元素个数:path.size();
- 还需要的元素个数为: k - path.size();
- 在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
优化代码(●ˇ∀ˇ●)
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方
path.push_back(i); // 处理节点
backtracking(n, k, i + 1);
path.pop_back(); // 回溯,撤销处理的节点
}
}
public:
vector<vector<int>> combine(int n, int k) {
backtracking(n, k, 1);
return result;
}
};
写博不易,请大佬点赞支持一下8~
代码随想录Day22的更多相关文章
- 代码随想录第十三天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素
第一题150. 逆波兰表达式求值 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 注意 两个整数之间的除法只保留整数部分. ...
- 代码随想录第八天 |344.反转字符串 、541. 反转字符串II、剑指Offer 05.替换空格 、151.翻转字符串里的单词 、剑指Offer58-II.左旋转字符串
第一题344.反转字符串 编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 s 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的额外空间解决这 ...
- 代码随想录-day1
链表 今天主要是把链表专题刷完了,链表专题的题目不是很难,基本都是考察对链表的操作的理解. 在处理链表问题的时候,我们通常会引入一个哨兵节点(dummy),dummy节点指向原链表的头结点.这样,当我 ...
- 代码随想录 day0 博客怎么写
前言 2.25日开始记录自己的博客生涯以及代码随想录训练营的每日内容 一.题目链接怎么找?怎么设置连接? 力扣题目链接1:力扣 二.正文怎么写? 二分查找 算法思路: 二分查找需要保证数组为有序数组同 ...
- 【LeetCode动态规划#05】背包问题的理论分析(基于代码随想录的个人理解,多图)
背包问题 问题描述 背包问题是一系列问题的统称,具体包括:01背包.完全背包.多重背包.分组背包等(仅需掌握前两种,后面的为竞赛级题目) 下面来研究01背包 实际上即使是最经典的01背包,也不会直接出 ...
- 代码随想录算法训练营day22 | leetcode 235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点
LeetCode 235. 二叉搜索树的最近公共祖先 分析1.0 二叉搜索树根节点元素值大小介于子树之间,所以只要找到第一个介于他俩之间的节点就行 class Solution { public T ...
- 代码随想录第七天| 454.四数相加II、383. 赎金信 、15. 三数之和 、18. 四数之和
第一题454.四数相加II 给你四个整数数组 nums1.nums2.nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 <= i, ...
- 代码随想录算法训练营day17 | leetcode ● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和
LeetCode 110.平衡二叉树 分析1.0 求左子树高度和右子树高度,若高度差>1,则返回false,所以我递归了两遍 class Solution { public boolean is ...
- 代码随想录算法训练营day13
基础知识 二叉树基础知识 二叉树多考察完全二叉树.满二叉树,可以分为链式存储和数组存储,父子兄弟访问方式也有所不同,遍历也分为了前中后序遍历和层次遍历 Java定义 public class Tree ...
- 代码随想录算法训练营day10 | leetcode 232.用栈实现队列 225. 用队列实现栈
基础知识 使用ArrayDeque 实现栈和队列 stack push pop peek isEmpty() size() queue offer poll peek isEmpty() size() ...
随机推荐
- ClickHouse的物化视图及MySQL表引擎
MySQL表引擎可以与MySQL数据库中的数据表简历映射,并通过SQL向其发起远程查询. MySQL表引擎可以与物化视图结合,来同步更新MySQL数据库中的数据. 语法: CREATE TABLE [ ...
- 02-HTML知识点
01 元素的介绍 02 元素的属性 03 元素的嵌套关系 04 HTML结构分析 4.1 文档声明[这个不叫元素] 4.2 html元素 4.3 head元素 主要用来写文档的配置信息 05 HTML ...
- 分享两个内置Google广告位的Typecho主题
前言 很多项目的开始都是因为情怀和热爱,"为爱发电"是一件很值得尊敬的事情,然而大量"为爱发电"的项目最后却不得不因"难以为继"而被迫停服. ...
- 『vulnhub系列』HACKABLE-II
『vulnhub系列』HACKABLE-II 下载地址: https://www.vulnhub.com/entry/hackable-ii,711/ 信息搜集: 使用nmap探测存活主机,发现主机开 ...
- Docker使用Dockerfile部署项目
什么是dockerfile? Dockerfile是一个包含用于组合映像的命令的文本文档.可以使用在命令行中调用任何命令. Docker通过读取Dockerfile中的指令自动生成镜像. 如何通过do ...
- 面试官:Java对象引用都有哪些类型?
哈喽,大家好,我是世杰. 本文我为大家介绍面试官经常考察的「Java对象引用相关内容」 照例在开头留一些面试考察内容~~ 面试连环call Java对象引用都有哪些类型? Java参数传递是值传递还是 ...
- 直播预告:Service Mesh 技术在美团的落地和挑战
一场突如其来的疫情加深了企业对数字化转型升级的渴望,作为新兴数字化业务的基础,云原生技术的价值日益凸显.当前,越来越多的企业逐步引入容器.微服务/Service Mesh 技术改造业务,实现数据库.P ...
- UE导入FBX、GLTF模型
楔子 虽然做了很多年的三维可视化,不过都主要还是web端开发为主(webgl,threejs,有兴趣的读者也可以关注下我的相关专栏).最近准备入手一下UE,顺便做一下知识梳理. 所以文章可能都是比较粗 ...
- thinkphp5 关于跨域的一些坑
1.首先在tp5的入口文件:public/index.php 在里面添加三行: // [ 应用入口文件 ] header("Access-Control-Allow-Origin:*&quo ...
- SMU Summer 2024 第一周周报 (zhaosang)
学到了很多,不仅仅是学习方面的,在学校学跟在家寒假对比,天差地别吧. 补题的过程中收获满满,最近练习二分三分,栈队列单调栈等习题,题目不简单,努力学习中.. 打比赛也是,也有打的很惨的时候,我自己需要 ...