leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记

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]]

(一)了解回溯算法 

leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记_第1张图片

leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记_第2张图片

leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记_第3张图片

  1. for 循环遍历集合区间,可以理解为一个节点有多少个孩子,这个for循环就执行多少次。
  2. backtracking(递归)自己调用自己。
  3. 实现递归由上图可以看出,for循环可以理解是横向遍历,backtracking 就是纵向遍历

 (二)backtracking + 图解 leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记_第4张图片

leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记_第5张图片

递归三步曲:

  • ① 首先,确定递归函数的参数返回值
  • ② 确定递归的终止条件
  • ③ 确定单层搜索的逻辑
void backtracking(参数) {
    if(终止条件) {
        存放结果;    
        return;        
    }
    for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表);//递归
        回溯,撤销处理结果
    }
}
  1. 一维数组:path 用来收集路径
  2. 二维数组:result 存放path,作为结果集
  3. startIndex 用来控制每次搜索的位置
class Solution {
public:
    vector path; // 用来存放符合条件单一结果
    vector> 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> combine(int n, int k) {
        bactracking(n,k,1);
        return result;
    }
};

(三)剪枝操作

leetCode 77.组合 + 回溯算法 (bactracking) + 剪枝 + 图解 + 笔记_第6张图片

class Solution {
private:
    vector> result;
    vector 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> combine(int n, int k) {
        backtracking(n, k, 1);
        return result;
    }
};

参考和推荐文章、视频:

代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://www.programmercarl.com/0077.%E7%BB%84%E5%90%88.html#%E6%80%9D%E8%B7%AF带你学透回溯算法-组合问题(对应力扣题目:77.组合)| 回溯法精讲!_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1ti4y1L7cv/?vd_source=a934d7fc6f47698a29dac90a922ba5a3

你可能感兴趣的:(leetCode,leetcode,回溯,组合,剪枝)