排列-组合-子集算法总结
概念
组合、排列、子集是 leetcode 中比较常见的题目系列,主要区别在于:
名称 | 概念 | 示例题目 |
---|---|---|
排列 | 每项结果有序,即[1,2] 与 [2,1]是两个结果 | 46. 全排列、47. 全排列 II、 |
组合 | 每项结果无序,即[1,2]与[2,1]是一个结果 | 39. 组合总和、216. 组合总和 III、40. 组合总和 II、77. 组合 |
子集 | 与组合类似,但会有额外的限制,比如数量等 | 78. 子集、90. 子集 II |
抽取类题目
元素没有重复也不能复选
nums
中的元素都是唯一的,每个元素最多可以使用一次。
- 排列伪代码
即题目 46. 全排列 的解:
1 | def back_track(self, nums, track_list, used_pos): |
- 组合伪代码
即 77. 组合 的解
1 | def back_track(self, n, start, k): |
元素重复但不能复选
- 排列伪代码
即 47. 全排列 II 的解
1 | def back_track(self, nums, track_list, used_pos): |
- 组合伪代码
即 90. 子集 II 的解
1 | def back_track(self, nums, start): |
元素无重复可以复选
- 排列伪代码
删除了去重逻辑,并且也不需要再考虑 used_pos
1 | def back_track(self, nums, track_list): |
- 组合伪代码
1 | def back_track(self, nums): |
求和类问题
和已知(target 已知)
典型题目 39. 组合总和 、40. 组合总和 II
39 题为组合类题目,但可以复选
1 | class Solution: |
40 题目为组合类问题,但不能复选
1 | class Solution: |
组数量已知(k已知)
典型题目 698. 划分为k个相等的子集
我实现的第一个代码是
1 | class Solution: |
这个实现是从数字的角度出发,判断每个数字是否应该进入某个桶,比较明显的超时了。
从桶的角度出发,如果当前的桶已经满足了要求,那么就只需要 k - 1 需要进一步的考虑。另外,bucket 与 track_sum 的设计,也是与之前的角度是相反的。并且同时使用到了 used_pos 和 start 的设计。
1 | class Solution: |
排列-组合-子集算法总结