首页 > 编程语言 >代码随想录算法训练营第二十四天| 理论基础 77. 组合

代码随想录算法训练营第二十四天| 理论基础 77. 组合

时间:2023-08-26 13:55:20浏览次数:41  
标签:剪枝 int 随想录 77 算法 第二十四 result 回溯 path

 

理论基础 

     卡哥建议:其实在讲解二叉树的时候,就给大家介绍过回溯,这次正式开启回溯算法,大家可以先看视频,对回溯算法有一个整体的了解。

    题目链接/文章讲解:https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

    视频讲解:https://www.bilibili.com/video/BV1cy4y167mM

 

 77. 组合  

      卡哥建议:对着 在 回溯算法理论基础 给出的 代码模板,来做本题组合问题,大家就会发现 写回溯算法套路。在回溯算法解决实际问题的过程中,大家会有各种疑问,先看视频介绍,基本可以解决大家的疑惑。本题关于剪枝操作是大家要理解的重点,因为后面很多回溯算法解决的题目,都是这个剪枝套路。 

     题目链接/文章讲解:https://programmercarl.com/0077.%E7%BB%84%E5%90%88.html

     视频讲解:https://www.bilibili.com/video/BV1ti4y1L7cv      剪枝操作:https://www.bilibili.com/video/BV1wi4y157er

     做题思路:

      暴力解法思路:当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环;如果n为100,k为50呢,那就50层for循环!

     那么回溯法就用递归来解决嵌套层数的问题。递归来做层叠嵌套(可以理解是开k层for循环),每一次的递归中嵌套一个for循环,那么递归就可以用于解决多层嵌套循环的问题了。回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了。

 

       图中可以发现n相当于树的宽度,k相当于树的深度。图中每次搜索到了叶子节点,我们就找到了一个结果。

     相当于只需要把达到叶子节点的结果收集起来,就可以求得 n个数中k个数的组合集合。

     回溯法三部曲(见卡哥文章)

  • 递归函数的返回值以及参数
  • 回溯函数终止条件
  • 单层搜索的过程

     path是一维数组,用来存放符合条件单一结果;result是二维数组,用来存放符合条件结果的集合。

     startIndex 就是防止出现重复的组合,在代码里是一个变量,从1开始。

     本题代码:

 1 class Solution {
 2 private:
 3     vector<vector<int>> result; // 存放符合条件结果的集合
 4     vector<int> path; // 用来存放符合条件结果
 5     void backtracking(int n, int k, int startIndex) {
 6         if (path.size() == k) {
 7             result.push_back(path);
 8             return;
 9         }
10         for (int i = startIndex; i <= n; i++) {
11             path.push_back(i); // 处理节点
12             backtracking(n, k, i + 1); // 递归
13             path.pop_back(); // 回溯,撤销处理的节点
14         }
15     }
16 public:
17     vector<vector<int>> combine(int n, int k) {
18         result.clear(); // 可以不写
19         path.clear();   // 可以不写
20         backtracking(n, k, 1);
21         return result;
22     }
23 };

     

     剪枝优化

     比如, n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了,因为(2,3,4),不含4个数。 在第二层for循环,从元素3开始的遍历都没有意义了。

 

 

    优化过程如下(看卡哥文章举例):

  1. 已经选择的元素个数:path.size();

  2. 还需要的元素个数为: k - path.size();

  3. 在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历

     剪枝优化后整体代码如下:

 1 class Solution {
 2 private:
 3     vector<vector<int>> result;
 4     vector<int> path;
 5     void backtracking(int n, int k, int startIndex) {
 6         if (path.size() == k) {
 7             result.push_back(path);
 8             return;
 9         }
10         for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方
11             path.push_back(i); // 处理节点
12             backtracking(n, k, i + 1);
13             path.pop_back(); // 回溯,撤销处理的节点
14         }
15     }
16 public:
17 
18     vector<vector<int>> combine(int n, int k) {
19         backtracking(n, k, 1);
20         return result;
21     }
22 };

 

 

标签:剪枝,int,随想录,77,算法,第二十四,result,回溯,path
From: https://www.cnblogs.com/romantichuaner/p/17646819.html

相关文章

  • 代码随想录算法训练营第二十三天| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜
     669. 修剪二叉搜索树    卡哥建议:这道题目比较难,比 添加增加和删除节点难的多,建议先看视频理解。   题目链接/文章讲解:https://programmercarl.com/0669.%E4%BF%AE%E5%89%AA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html   视频讲解:https://www.......
  • 代码随想录算法训练营第二十二天| 235. 二叉搜索树的最近公共祖先 701.二叉搜索树
      235. 二叉搜索树的最近公共祖先    卡哥建议:相对于 二叉树的最近公共祖先 本题就简单一些了,因为 可以利用二叉搜索树的特性。   题目链接/文章讲解:https://programmercarl.com/0235.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%B......
  • 代码随想录第三天|203.移除列表元素;707.设计链表;206.反转链表
    今天最大的收获不是学会了几道题,而是突然改变了自己之前的想法,总想刷一遍就能把题弄回,这样在遇到难题时会拖延很长的时间,备受挫折,做一两道题就再也不想做了,刷题也就终止了应该做好刷三遍题的准备,第一遍,大量看题,看解题思路,在看题的过程中积累知识和解题技巧,不要迷恋在某一道题上,看......
  • [代码随想录]Day27-贪心算法part01
    题目:455.分发饼干思路:贪心,思路是尽量先给胃口值小的分,饼干也是从小的开始分:如果饼干满足了胃口值,结果+1换下一个人,下一个饼干如果饼干满足不了胃口值,换下一个饼干(满足不了胃口值小的一定满足不了大的)代码:funcfindContentChildren(g[]int,s[]int)int{res:=......
  • 代码随想录第二天|977.有序数组的平方;209.长度最小的子数组;59.螺旋矩阵II,总结
    今天的这三道题每道题对我来说都不简单,有序数组的平方和长度最小的子数组这两道题还能用暴力求解,螺旋矩阵看着简单却没有思路,磨了半小时还是决定直接看讲解有序数组平方和用的双指针的思想,代码如下:1classSolution{2public:3vector<int>sortedSquares(vector<int......
  • [代码随想录]Day26-回溯算法part06
    题目:332.重新安排行程思路:其实这里已经是图的部分了,回溯应该也可以。Hierholzer算法解决欧拉问题代码:funcfindItinerary(tickets[][]string)[]string{var(m=map[string][]string{}res[]string)for_,ticket:=rangeticket......
  • 代码随想录第一天|704.二分查找、27.移除元素
    二分查找对数组的要求有两点:有序无重复元素,若有重复元素则返回的元素下标不唯一边界条件是while(left<=right)代码其实是很好理解的点击查看代码classSolution{public:intsearch(vector<int>&nums,inttarget){intlength=nums.size();......
  • Python基础入门学习笔记 077 GUI的终极选择:Tkinter14
    Tkinter提供了三种标准对话框模块,分别是:messagebox、filedialog、colorchoosermessagebox(消息对话框)实例1:askokcancel函数1fromtkinterimport*23print(messagebox.askokcancel("FishCDemo","发射核弹?"))45mainloop() 实例2:askquestion函数 实例3:asire......
  • [代码随想录]Day25-回溯算法part05
    题目:491.递增子序列思路:核心问题——同层去重,这一题不能够重新排序因此不可以用i>index&&nums[i]==nums[i-1]来去重,而是每一层开一个map来判断该数是否出现过代码:var(res[][]intpath[]int)funcfindSubsequences(nums[]int)[][]int{res=make(......
  • P8772 [蓝桥杯 2022 省 A] 求和 题解
    蒟蒻第一次发题解qwq$S=a_1\timesa_2+a_1\timesa_3+a1\timesa_n+a_2\timesa_3+···+a_n-2\timesa_n-1+a_n-1\timesa_n$从样例来看41369这道题就是要求$1\times3+1\times6+1\times9+3\times6+3\times9+6\times9$我们可以把这个算式分成几个部分$(1\t......