力扣日记1.21-【回溯算法篇】77. 组合

这篇具有很好参考价值的文章主要介绍了力扣日记1.21-【回溯算法篇】77. 组合。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

力扣日记:【回溯算法篇】77. 组合

日期:2023.1.21
参考:代码随想录、力扣
终于结束二叉树了!听说回溯篇也是个大头,不知道这一篇得持续多久了……

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

题解

class Solution {
#define SOLUTION 2
public:
#if SOLUTION == 1
    // 定义两个全局变量
    vector<vector<int>> result; // 存放结果集
    vector<int> path;   // 存放当前组合

    // 转换为树结构,树的宽度为当前集合长度(用for循环横向遍历),树的深度为递归层数(组合个数k)
    vector<vector<int>> combine(int n, int k) {
        backtracking(n, k, 1);
        return result;
    }
    
    // 回溯三部曲
    // 1. 返回值为void,参数为原参数n、k以及表示当前集合开始遍历的起始位置
    void backtracking(int n, int k, int startindex) {
        // 2. 终止条件
        if (path.size() == k) { // 当前组合(大小)已满足条件
            // 存放结果
            result.push_back(path);
            return;
        }
        // 3. 回溯逻辑
        // for 循环横向遍历当前集合
        for (int i = startindex; i <= n; i++) { // index:[1, n]
            // 处理节点
            path.push_back(i);
            // 递归
            backtracking(n, k, i+1);    // 下一次从i+1开始遍历
            // 回溯,撤销处理节点
            path.pop_back();
        }
    }
#elif SOLUTION == 2 // 考虑剪枝优化
    // 剪枝优化主要体现在 for 循环横向遍历处
    // 如果剩余可遍历(取值)的元素数量不足以达到组合长度,则没有必要遍历
    // 即当前路径长度 path.size() + x >= k, 其中x为剩余可遍历的元素个数 x = n - startindex + 1(加1因为是左闭)
    // 所以startindex(即for中的i) 需 <= path.size() + n + 1 - k
    
    // 定义两个全局变量
    vector<vector<int>> result; // 存放结果集
    vector<int> path;   // 存放当前组合

    // 转换为树结构,树的宽度为当前集合长度(用for循环横向遍历),树的深度为递归层数(组合个数k)
    vector<vector<int>> combine(int n, int k) {
        backtracking(n, k, 1);
        return result;
    }
    
    // 回溯三部曲
    // 1. 返回值为void,参数为原参数n、k以及表示当前集合开始遍历的起始位置
    void backtracking(int n, int k, int startindex) {
        // 2. 终止条件
        if (path.size() == k) { // 当前组合(大小)已满足条件
            // 存放结果
            result.push_back(path);
            return;
        }
        // 3. 回溯逻辑
        // for 循环横向遍历当前集合
        for (int i = startindex; i <= path.size() + n + 1 - k; i++) { // 剪枝优化
            // 处理节点
            path.push_back(i);
            // 递归
            backtracking(n, k, i+1);    // 下一次从i+1开始遍历
            // 回溯,撤销处理节点
            path.pop_back();
        }
    }
#endif
};

复杂度

时间复杂度:
空间复杂度:

思路总结

  • 回溯算法理论基础
  • 回溯算法模板框架:
    void backtracking(参数) {
        if (终止条件) {
            存放结果;
            return;
        }
    
        for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
            处理节点;
            backtracking(路径,选择列表); // 递归
            回溯,撤销处理结果
        }
    }			
    
  • 将组合问题抽象为树形结构(N叉树):
    力扣日记1.21-【回溯算法篇】77. 组合,算法,leetcode,职场和发展

    每个框即为每层递归的for循环,取值即为处理节点,最下面即为达到组合长度(终止条件)后存放结果

  • 回溯法三部曲:
    • 递归函数的返回值以及参数:
      • 为了简化参数,分别为存放整体结果集和单一组合定义两个全局变量,resultpath
      • 返回值一定为void,传递参数除了原始参数n和k,还要加一个startindex,用来记录本层递归的中,集合从哪里开始遍历
    • 终止条件:当前组合(大小)已满足条件
      • 此时将组合保存进结果集
    • 单层搜索的过程:
      • for 循环横向遍历当前集合(从startindex开始遍历):
        • 首先处理节点(即将当前值放入path)
        • 接着进行递归(起始位置要+1)
        • 再是回溯(即撤销处理节点,将值弹出)
  • 关于剪枝优化:
    • 剪枝优化主要体现在 for 循环横向遍历处:

      • 如果剩余可遍历(取值)的元素数量不足以达到组合长度,则没有必要继续遍历
      • 即当前路径长度 path.size() + x >= k, 其中x为剩余可遍历的元素个数 x = n - startindex + 1(加1因为是左闭)
      • 所以startindex(即for中的i) 需 <= path.size() + n + 1 - k
    • 力扣日记1.21-【回溯算法篇】77. 组合,算法,leetcode,职场和发展

    • 对于原来的不剪枝的情况,会在遍历到叶子节点(即for循环遍历完后)结束当前层递归,但由于未达到组合长度,所以在递归中不会添加到结果集。文章来源地址https://www.toymoban.com/news/detail-816320.html

到了这里,关于力扣日记1.21-【回溯算法篇】77. 组合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode:77. 组合——回溯法,是暴力法?

    🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 题目描述 :给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 来源:力扣(LeetCode) 难度: 中等 提示: 1 = n = 20 1 = k = n 示例 1: 输入:

    2023年04月18日
    浏览(24)
  • 【回溯算法】77. 组合

    回溯结束条件 track长度等于k 然后收集当前的路径 遍历所有的节点 然后选择当前节点 通过start参数控制遍历 避免产生重复的子集 移除当前的选择

    2024年02月09日
    浏览(28)
  • day24 | 回溯算法基础、77. 组合

    目录: 回溯法理论基础 https://programmercarl.com/回溯算法理论基础.html#题目分类大纲如下 回溯法,一般可以解决如下几种问题: 组合问题:N个数里面按一定规则找出k个数的集合 切割问题:一个字符串按一定规则有几种切割方式 子集问题:一个N个数的集合里有多少符合条件的

    2024年02月11日
    浏览(33)
  • 77. 组合(回溯)

    和上一道回溯的题思路大致相同: 从前往后依次遍历,之后拼接的数字为当前数字 cur 的之后的数字,直到 list 的长度等于 k ,将 list 加入到 ans 当中。 特别注意: if 和 else 的区分,否则 if 要及时 return 回溯的时候新的 cur 值应该是 i+1 而不是 cur+1 ans.add(new ArrayList(list)); 在

    2024年02月02日
    浏览(34)
  • leetcode216. 组合总和 III(回溯算法-java)

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/combination-sum-iii 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件: 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。 示例 1: 输

    2024年02月10日
    浏览(34)
  • 算法学习——LeetCode力扣回溯篇2

    40. 组合总和 II - 力扣(LeetCode) 描述 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 示例 示例 1: 输入: candidates = [10,1,2,7

    2024年02月20日
    浏览(28)
  • LeetCode算法题解(回溯)|39. 组合总和、40. 组合总和 II、131. 分割回文串

    题目链接:39. 组合总和 题目描述: 给你一个  无重复元素  的整数数组  candidates  和一个目标整数  target  ,找出  candidates  中可以使数字和为目标数  target  的 所有   不同组合  ,并以列表形式返回。你可以按  任意顺序  返回这些组合。 candidates  中的  同一个  数

    2024年02月05日
    浏览(48)
  • 力扣77. 组合

    思路: 找到一个长度为 nnn 的序列 aaa 的所有子序列,代码框架: 本题递归结束条件为序列中元素为 k,即: 已经构建的序列S\\\',剩余的数不足以构成满足条件的序列 S: 剩余的数长度 n - (cur - 1) size(S\\\') + (n - (cur - 1)) size(S) = k 这种情况也需要退出递归 综上,完整代码

    2024年01月16日
    浏览(28)
  • C++力扣题目77--组合

    给定两个整数  n  和  k ,返回范围  [1, n]  中所有可能的  k  个数的组合。 你可以按  任何顺序  返回答案。 示例 1: 示例 2: 提示: 1 = n = 20 1 = k = n 本题是回溯法的经典题目。 直接的解法当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输

    2024年01月17日
    浏览(31)
  • 【Leetcode60天带刷】day27回溯算法——39. 组合总和,40.组合总和II,131.分割回文串

    ​ 39. 组合总和 给你一个  无重复元素  的整数数组  candidates  和一个目标整数  target  ,找出  candidates  中可以使数字和为目标数  target  的 所有   不同组合  ,并以列表形式返回。你可以按  任意顺序  返回这些组合。 candidates  中的  同一个  数字可以  无限制重复

    2024年02月11日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包