本文始发于个人公众号:TechFlow,原创不易,求个关注

今天是LeetCode专题第56篇文章,我们一起来看看LeetCode第90题,子集II(Subsets II)。

这题的官方难度是Medium,通过率46.8%,点赞1686,反对73。看得出来是一道偏基础,然后质量很高的题。既然有Subsets II自然有Subsets I,它的前作是78题,和78题相比,题意稍稍有些改动,如果没做过78题的,建议可以先看下,有个对比。

LeetCode 78,面试常用小技巧,通过二进制获得所有子集

题意

给定一个包含重复元素的数组,要求生成出这些元素能够构成的所有子集。注意,子集包括空集和全集

在之前的LeetCode78题当中,给定用来生成子集的数组当中不包含重复的元素。这也是这两题当中最大的差别。

样例

Input: [1,2,2]
Output:
[[2],[1],[1,2,2],[2,2],[1,2],[]
]

题解

全排列的问题也好,获取子集也好,这些问题都已经算是老生常谈了,我们之前做过不少。这些问题经过转化之后,本质上还是搜索问题。我们在样本空间当中搜索所有合法的解,存储起来。

这道题的前身LeetCode78题用的正解也是搜索的解法,对于使用搜索算法来解这道题问题不大,但问题是针对数组当中的重复元素我们应该怎么样来处理。

最简单也是最容易想到的方法当然是先把所有的子集全部找到之后,我们再进行去重。如果采用这样的方法,还有一个便利是我们可以不用递归,而是可以通过二进制枚举的方法获取所有的子集。但也有一个问题,问题就是复杂度。我们把集合当中的每一个数字都看成是独立的,那么对于每一个数字来说都有取和不取两种方案。对于n个数字来说,方案总数当然就是

。并且我们还需要对这
个集合进行去重,这带来的开销可想而知。

当然针对这个问题我们也有解决方案比如可以用hash算法将一个集合hash成一个数,如果hash值一样说明集合的构成相同。这样我们就可以通过对数字去重来实现集合去重了。

但这样仍然不是完美的,首先hash算法也不是百分百可靠的,也可能会出现hash值碰撞的情况。其次,这种方案的实现复杂度也很大,我们找出所有集合之后再通过hash算法进行过滤,整个过程非常麻烦。

很明显,这题一定还存在更好的方法。

既然事后找补不靠谱,那么我们可以试着事前避免。也就是说我们在搜索所有子集的时候就设计一种机制可以过滤掉重复的集合或者是保证重复的集合不会出现。我们可以分析一下重复的集合出现的原因,两个集合完全一样,说明其中的元素构成完全一致。元素的构成一致又有两种可能,第一种是重复的获取,比如[1, 3],我们先拿1再拿3和先拿3再拿1本质上是一样的。还有一种可能是元素的重复导致的集合重复,比如[1, 3]假如我们候选的1不止一个,那么拿不同的1也会被认为是不同的方案。

针对第一种情况出现的重复非常简单,我们可以对元素进行排序,之后限定拿取元素的顺序。只能从左拿到右,不能先拿右边的元素再回头拿左边的元素,这样就禁止了第一种情况导致的重复。这个方法我们曾经在很多问题当中用到过,就不详细介绍了。

下面来说说第二种情况,就是重复元素导致的重复集合。这一点需要结合代码来仔细说明,我们来看一段经典的搜索代码:

def 

这一段是一个经典的搜索代码,我们在for循环当中执行的其实是一个枚举操作,也就是枚举这一轮我们要拿取哪一个元素。这里我们限制了选择的范围只能在上一次选择元素的右侧,也就是上文当中说的针对第一种情况的方案。假设我们当前候选的元素是[1, 1, 3, 3],这里虽然有4个元素,但是值得我们搜索的其实只有两个,就是1和3。因为第二个1和第二个3都没有任何用处,只会导致结果重复。

并且假设我们希望得到[1, 1]这样的结果,只能通过拿取左侧的1实现。也就是说如果出现重复的元素,我们只需要考虑第一个出现的,其余都没有考虑的必要

为了更加形象, 我们画出这一段的搜索树。这里我们为了简化图示,只画了[1, 1, 3]三个数的情况。可以看出我们选第一个1和第二个1,都构建出了[1, 3]这个集合,这是重复的。并且我们可以发现第二个1的所有情况第一个1都已经包括了,所以这一整个分支都是多余的,可以剪掉。

最后,我们把上面的细节全部串起来写出代码:

class 

总结

到这里,我们关于这道题的介绍就结束了。从代码上来看,这道题的代码不长,涉及到需要推理的细节也并不多,总体的难度并不大。但作为一道搜索问题,它仍然非常有价值。如果你能自己思考推导得出正确的递归代码,那么说明你对递归的理解已经可以算是合格了,所以这题也非常适合面试,要准备找工作的小伙伴,可以仔细刷刷。

今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。

子集和问题 算法_LeetCode 90 | 经典递归问题,求出所有不重复的子集II相关推荐

  1. 子集和问题 算法_LeetCode刷题实战90:子集 II

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  2. 子集和问题 算法_LeetCode 题解 | 78.子集

    力扣 78. 子集 (点击查看题目) 力扣​leetcode-cn.com 题目描述 给定一组 不含重复元素 的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. ...

  3. python斐波那契前20递归_算法python实现经典递归问题(汉诺塔, 斐波那契数列,阶乘)...

    经典递归 汉诺塔问题 背景故事 传说印度某间寺院有三根柱子,上串64个金盘.寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子:预言说当这些盘子移动完毕,世界就会灭亡.这个传说叫做梵天寺之塔问题( ...

  4. C++两个函数可以相互递归吗_[算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进

    [算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进 从学习写代码伊始, 总有个坎不好迈过去, 那就是遇上一些有关递归的东西时, 看着简短的代码, 怎么稀里糊涂就出来了. ...

  5. 【算法基础】经典例题说递归

    目录 [算法基础]经典例题说递归 递归简介 递归的适用范围 递归的基本思路 经典例题解析 移梵塔 题目描述 题目分析 题解 九连环 题目描述 题目分析 题解 更新日志 [算法基础]经典例题说递归 递归 ...

  6. 算法设计方法:递归的内涵与经典应用

    摘要: 大师 L. Peter Deutsch 说过:To Iterate is Human, to Recurse, Divine.中文译为:人理解迭代,神理解递归.毋庸置疑地,递归确实是一个奇妙的 ...

  7. [算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进

    [算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进 从学习写代码伊始, 总有个坎不好迈过去, 那就是遇上一些有关递归的东西时, 看着简短的代码, 怎么稀里糊涂就出来了. ...

  8. 刘汝佳《算法竞赛入门经典》---总结

    刘汝佳:<算法竞赛入门经典> 三步: 基本的数据结构+算法知识: 数论等数学基本知识: 锻炼联想建模能力.知识与实际相结合,解决实际问题! 第一章:程序设计入门 1.a/b 当a.b为整数 ...

  9. 《算法竞赛入门经典——训练指南》第一章相关内容

    #<算法竞赛入门经典--训练指南>第一章相关内容 希望各位大牛能指导! 红色为已经做了的...黄色背景是还有不懂地方,希望在年前能刷完第一章啊.... 更新版.google上貌似又加了ex ...

最新文章

  1. Mysql探究之null与not null
  2. 字节跳动程序员说自己因为颜值太高被男同事集体排挤!失望透顶!准备转行!...
  3. bzoj 4753: [Jsoi2016]最佳团体
  4. 内部类--毕向东Java基础教程学习笔记
  5. java handlersocket_HandlerSocket java客户端
  6. HTTP缓存及其使用
  7. 关于程序中查询效率的问题
  8. linux ftp 工作过程,linux中ftp的安装过程记录[运维篇]
  9. mysql 锁 代码_MySQL中的锁实例
  10. 我对Spring的理解
  11. 把 charles,Fiddler 证书安装到安卓根目录,解决安卓微信 7.0 版本以后安装证书也无法抓包问题,需要 root
  12. python 读取wifi数据_通过Python实现WiFi测试数据分析
  13. HashSet源码阅读
  14. 解决:Eclipse SVN一直要求输出登陆密码
  15. 代价敏感随机森林Python附代码
  16. 对接ERP和MES,使用低代码定制生产计划管理(APS)系统
  17. 【线性代数】P8 逆矩阵矩阵方程以及逆矩阵的性质
  18. 勒索病毒锁死文件加密
  19. 马斯克让位?特斯拉中国一把手被曝将接任全球CEO,内部回应:您觉得是真的吗?...
  20. Linux系统鲁大师查看CPU、内存、显卡信息

热门文章

  1. 【Flink】Flink 不支持部分 task 结束后进行 checkpoint
  2. 【算法】剑指 Offer 45. 把数组排成最小的数 【重刷】
  3. 75-100-020-测试-MySQL 单表优化案例
  4. 【java】java JUC 同步器框架 AQS AbstractQueuedSynchronizer源码图文分析
  5. 【Spring】Could not commit JPA transaction RollbackException: Transaction marked as rollbackOnly
  6. 95-270-019-源码-指标监测-常用监控指标
  7. Java中使用ProcessBuilder启动、管理应用程序
  8. Spark的ShuffleManager
  9. 深入分析 RestController 与 Controller 的区别,你真的了解吗?
  10. 大数据是如何基于 Flink 进行实时计算的?