77. 组合 - 力扣(LeetCode)
给定两个整数 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]]
(一)了解回溯算法
- for 循环遍历集合区间,可以理解为一个节点有多少个孩子,这个for循环就执行多少次。
- backtracking(递归)自己调用自己。
- 实现递归由上图可以看出,for循环可以理解是横向遍历,backtracking 就是纵向遍历
(二)backtracking + 图解
递归三步曲:
- ① 首先,确定递归函数的参数和返回值
- ② 确定递归的终止条件
- ③ 确定单层搜索的逻辑
void backtracking(参数) {if(终止条件) {存放结果; return; }for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表);//递归回溯,撤销处理结果}
}
- 一维数组:path 用来收集路径
- 二维数组:result 存放path,作为结果集
- startIndex 用来控制每次搜索的位置
class Solution {
public:vector<int> path; // 用来存放符合条件单一结果vector<vector<int>> result; // 存放符合条件结果的集合void bactracking(int n,int k,int startIndex) {// 回溯函数终止条件if(path.size() == k) { // 用result二维数组,把path保存起来,并终止本层递归result.push_back(path);return;}// 单层搜索的过程for(int i=startIndex;i<=n;i++) { // 控制树的横向遍历 path.push_back(i); // 处理节点bactracking(n,k,i+1); // 递归:控制树的纵向遍历,注意下一层搜索要从 i + 1 开始path.pop_back(); // 回溯,撤销处理的节点}}vector<vector<int>> combine(int n, int k) {bactracking(n,k,1);return result;}
};
(三)剪枝操作
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++) { // 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;}
};
参考和推荐文章、视频:
代码随想录 (programmercarl.com)https://www.programmercarl.com/0077.%E7%BB%84%E5%90%88.html#%E6%80%9D%E8%B7%AF带你学透回溯算法-组合问题(对应力扣题目:77.组合)| 回溯法精讲!_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1ti4y1L7cv/?vd_source=a934d7fc6f47698a29dac90a922ba5a3