本文介绍组合算法,组合算法有很多,这里只介绍其中一种的两种形式。
全排列:全排列算法
组合:本文
子集算法:求子集算法

组合

leetcode实战:组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

从n个数字里面选k个数字,那么至少有一个数字落在这n个数字里面的最后几位或者最前几位,接下来分别考虑这两种情况:

1. 从后开始选:


从n个数字里面选k个,如上图,每个组合中至少有一位数字会落在[k,n]中(当1~k-1都被选中时),也就是说每个组合中一定至少存在一个[k,n]中的数字,因此我们依次从[k,n]中选择一个数字作为我们k组合中的第一个被选择的数字(第1位,当然第2,3…位也有可能处于[k,n]中),为了找到所有组合,必须逆序从n→k选择

如上图,首先我们选择n作为第一个数字,那么接下来相当于要从[1,n-1]中选择剩下的k-1个数字,这样就回到了最初开始的地方,只是两个参数有变:从n-1个数字中选择k-1个数字。接下来也是同样的理解,一定有一个数字存在[k-1,n-1]中,同样逆序选择[k-1,n-1]中的数字,这就实现了将一个大问题不断拆分成相同的小问题,得到了递归步骤,最后按照上述流程选择数字直到k=0,找到递归边界。当k=0时证明已经找到一个组合,将这个组合存储下来然后退回上层继续遍历寻找其他可能。

逆序选择的原因就是上述流程可以保证找到包含数字n的所有组合,且不产生重复。更具体的来说,如果当前在寻找k个数字中的第i位(第i层递归),那么该流程可以找到[a,b]中的数字位于第i位的所有可能(假设当前参数是从前a个整数中选b个. b<=k, a<=n)。

当n作为第一位被选择的所有可能的组合寻找结束后,再逆序选择n-1作为第一位,继续递归从n-2个数中选择k-1个数字,当选择i作为第一位数字时,则继续从剩下i-1个数字中选k-1个,依次递归直到找到所有可能的组合。
代码如下:

class Solution:def combine(self, n: int, k: int) -> List[List[int]]:ans=[]def sub_combine(n,k,lst=[]):  #n个数里面选k个,保存在lst里if(k==0):    #已经选完ans.append([i for i in lst])returnfor i in range(n,k-1,-1):  #n中选k个,那么一定有一个数存在于[k,n]中,因此从这里一个一个取lst.append(i)          #注意是逆序选,将问题进行划分sub_combine(i-1,k-1)   #选定i后,剩下的存在于[1,i-1]中,即i-1个数中选k-1个lst.pop()          sub_combine(n,k)return ans

2. 从前开始选:

如果我们选择从头开始选择数字,同理,如下图,至少会有一个数字落在[1, n-k+1]中(此处说法并不眼严谨,但为了方便理解先这么写)。因此,我们也可以依次从[1,n-k+1]中顺序选择数字。可以看出,从前开始选和从后开始选这两种方法是一一对应的关系,其中的分析也一致,故不再赘述。

唯一需要注意的点是,在从前开始选的方法中,我们还需要一个初始索引start,用来指示从哪个初始点开始选择数字。以一个例子来说明。

如上图,如果我们第一个数字从[1,n-k+1]中选出了数字1,那么下一个数字必然不能是1,所以应当从1后面的数字开始选,而“后面这个数字”就意味着需要一个索引值来表明到底是从哪个数字开始选,也就是选择的范围是多少。

从后开始选的方法中之所以没有要求一个终止索引,是因为它是逆序选择数字,每次递归的函数sub_combine(i-1,k-1)中的i-1除了表示从i-1个数字中选择k-1个数字,还表明了终止索引为i-1,即从[1,i-1]这个范围中选择k-1个数字

因此,在从前开始选的方法中要显式使用start索引,每当我们选择好一个数字i之后,我们需要在下一次递归中明确写出,剩下的数字应该从[i+1,n]中选择。因此sub_combine函数变为sub_combine(start,n,k),即从[start,n]中选择k个数字,start在递归时为i+1,那么就是从[i+1,n]中选择k-1个数字(对应1中方法的从[1,i-1]中选择k-1个数字)。所以严谨地说,也就是从[start,n]中产生一个k组合,至少有一个数字落在范围为[start,n-k+2]中。
代码如下:

class Solution:def combine(self, n: int, k: int) -> List[List[int]]:ans=[]def sub_combine(start,n,k,lst=[]):  #n个数里面选k个,保存在lst里if(k==0):    #已经选完ans.append([i for i in lst])returnfor i in range(start,n-k+2):  #一定有一个数存在于[start,n-k+2]中lst.append(i)          sub_combine(i+1,n,k-1)   #选定i后,剩下的存在于[i+1,n]中lst.pop()          sub_combine(1,n,k)return ans

组合算法/全排列算法/求子集算法相关推荐

  1. 全排列算法(无重复数字全排列/有重复数字全排列)/ 组合算法/ 求子集算法

    写在前面 全排列 1 无重复数字全排列 1.1 紫书版本 1.2 回溯法 2 有重复数字全排列 复盘易错点(可跳过) 写在前面 很久很久以前就想写的一篇博客,因为懒一直没开工,但是学习全排列算法算是我 ...

  2. 全排列邻位对换法c语言算法,全排列及相关扩展算法(六)——全排列最蛋疼的算法:邻位对换法...

    1.引入原因:在此之前我们实现全排列本质上都是采用单向交换的思路,当交换到末端便要回溯至上一层面,如果我们采用双向的交换,便可以不断地交换下去,于是产生了邻位对换法.邻位对换法在找下一个排列的方法上在 ...

  3. hash算法_数据库中间件分片算法之hash

    前言 夜深人静的时候,打开云音乐,点上一曲攀登,带上真无线蓝牙耳机,瞬间燃到爆,键盘打字如飞倦意全无. 分片规则 这几天有人问我,dble和MyCat到底有什么不同.其实dble作为MyCAT的同门, ...

  4. 数字拆分问题算法回溯_回溯算法:求子集问题!

    给「代码随想录」一个星标吧! ❝ 认识本质之后,这就是一道模板题 通知:我将公众号文章和学习相关的资料整理到了Github :https://github.com/youngyangyang04/le ...

  5. java数组求子集_回溯算法:求子集问题!

    给「代码随想录」一个星标吧! ❝ 认识本质之后,这就是一道模板题 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums ...

  6. java数组排列组合_java算法题--递归求数组中数字排列组合问题

    java算法题–递归求数组中数字排列组合问题 题目:有一个数组{1,2,3},输出数组中数字的所有可能组合: 比如:123.132.213- 解题思路 通过递归不停的交换数组中的两个数(当然,肯定是有 ...

  7. 不相交集的求并算法(按集合大小求并+按高度求并)

    [0]README 0.1)本文总结于 数据结构与算法分析, 但源代码均为原创,旨在实现 不相交集ADT的两个操作:合并集合union+查找集合find: 0.2) 不相交集ADT 的 Introdu ...

  8. java算法排列式_JAVA 蓝桥杯算法 全排列 背公式即可

    什么是全排列? 所谓全排列就是把几个字符或数字(以下称为元素),进行全部排列 例如:字符串 abc 那么就可以这样排abc acb bac bca cab cba 把全部元素能用到的排列方式进行全部排 ...

  9. 数据结构(六):图的概念、存储方式、基本操作、最小生成树、最短路径、有向无环图、关键路径 | Prim、Kruskal算法 | BFS、Dijkstra、Floyd算法 | 拓扑排序 | 求关键路径

    文章目录 第六章 图 一.图 (一)图的定义 (二)图逻辑结构的应用 (三)无向图.有向图 (四)简单图.多重图 (五)顶点的度.入度.出度 (六)顶点-顶点的关系描述 (七)连通图.强连通图 (八) ...

最新文章

  1. iOS App与iTunes文件传输的方法和对iOS App文件结构的说明
  2. 第十七届全国大学智能车竞赛STC芯片申请方法
  3. 复习笔记--计算机网络
  4. 在Servlet中将JavaBean对象传递到JSP页
  5. 做运营,你需要“一张画布绘到底”
  6. Scala的集合类中的map方法和count 方法
  7. 【工具】PC端调试手机端 Html 页面的工具
  8. 这所双非高校硕士生一作发Science!系学校上半年第13篇CNS!
  9. 安徽省农商行计算机类考试,2017安徽农商行备考:计算机的系统组成
  10. java集合框架中迭代器的作用_Java中的集合框架之迭代器
  11. tas5424_TAS5424ATDKDQ1
  12. 黎曼猜想--论文笔记《On the Number of Primes Less Than a Given Magnitude》
  13. 基于大型数字视频监控系统解决方案
  14. EI检索的期刊要怎么区别是否是EI检索
  15. Toad 中的compare使用方法
  16. RT-Thread 驱动 PIN 设备
  17. openCV中watershed的使用
  18. kafka-topic管理
  19. lg-1 x 怎么算_黑洞是怎么形成的
  20. 数据库----数据查询

热门文章

  1. Word出现向程序发送命令时出现问题解决方法。
  2. google chrome浏览器离线包20190326
  3. 苹果x与苹果xs的区别_x与xs的区别
  4. Python+Socket实现多人聊天室,功能:好友聊天、群聊、图片、表情、文件等
  5. C#语言实例源码系列-实现桌面右下角Pop弹窗
  6. 联想rd450x服务器风扇转速调节
  7. 计算机网络与网络营销的关联性,网络营销:网络营销的特点列举及延伸解析
  8. 银行家算法c语言博客,操作系统之银行家算法
  9. [源码和文档分享]基于Android平台的个人理财软件的设计与实现
  10. 如何轻松的将文字转语音