Given an integer array nums
of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
Example 2:
Input: nums = [0]
Output: [[],[0]]
Constraints:
-
1 <= nums.length <= 10
-
-10 <= nums[i] <= 10
-
All the numbers of
nums
are unique.
方法一:回溯算法
思路分析
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。
那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!
那么,什么时候for可以从0开始呢?求排列问题的时候,就要从0开始,因为集合是有序的,{1, 2} 和{2, 1}是两个集合。
以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:
回溯三弄
函数签名
参数含义如下:
-
List<Integer> path
:为子集收集元素。 -
int[] originalArray
:一开始传入的原数组。 -
int startIndex
:下一递归其实索引。 -
List<List<Integer>> result
:存放子集组合。
代码如下:
private void backtracking(List path, int[] originalArray,
int startIndex, List<List> result) {}
终止条件
观察思路分析的图,发现剩余集合为空的时候,就是叶子节点。也就是startIndex已经等于数组的长度了,就终止了,因为没有元素可取了,代码如下:
if(startIndex == originalArray.length) {
return;
}
其实可以不需要加终止条件,因为startIndex == originalArray.length
,本层for循环本来也结束了。
遍历顺序
求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树。
代码如下:
for (int i = startIndex; i < originalArray.length; i++) {
path.add(originalArray[i]);
backtracking(path, originalArray, i + 1, result);
path.remove(path.size() - 1);
}
方法二:BFS
Using [1, 2, 3] as an example, the iterative process is like:
-
Initially, one empty subset [[]]
-
Adding 1 to []: [[], [1]];
-
Adding 2 to [] and [1]: [[], [1], [2], [1, 2]];
-
Adding 3 to [], [1], [2] and [1, 2]: [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]].
方法三:位操作
| 十进制 | 二进制 |
| — | — |
| 0 | 000 |
| 1 | 001 |
| 2 | 010 |
| 3 | 011 |
| 4 | 100 |
| 5 | 101 |
| 6 | 110 |
| 7 | 111 |
对例一来说:
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
让二进制与无重集合相结合,0表示对应的数不加入集合,1表示对应的数加入集合,如下表:
| - | nums[2]:3 | nums[1]:2 | nums[0]:1 | 子集 |
| — | — | — | — | — |
| 0 | 0 | 0 | 0 | [] |
| 1 | 0 | 0 | 1 | [1] |
| 2 | 0 | 1 | 0 | [2] |
| 3 | 0 | 1 | 1 | [1,2] |
| 4 | 1 | 0 | 0 | [3] |
| 5 | 1 | 0 | 1 | [1,3] |
| 6 | 1 | 1 | 0 | [2,3] |
| 7 | 1 | 1 | 1 | [1,2,3] |
What a happy accident!
参考资料
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后希望可以帮助到大家!
千千万万要记得:多刷题!!多刷题!!
之前算法是我的硬伤,后面硬啃了好长一段时间才补回来,算法才是程序员的灵魂!!!!
篇幅有限,以下只能截图分享部分的资源!!
(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集)
(2)刷的算法题(还有左神的算法笔记)
(3)面经+真题解析+对应的相关笔记(很全面)
(4)视频学习(部分)
ps:当你觉得学不进或者累了的时候,视频是个不错的选择
在这里,最后只一句话:祝大家offer拿到手软!!
!!!
篇幅有限,以下只能截图分享部分的资源!!
(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集)
[外链图片转存中…(img-BbSLWAoq-1711760700792)]
(2)刷的算法题(还有左神的算法笔记)
[外链图片转存中…(img-OIMWuGAX-1711760700793)]
(3)面经+真题解析+对应的相关笔记(很全面)
[外链图片转存中…(img-RyaE1Mc7-1711760700793)]
(4)视频学习(部分)
ps:当你觉得学不进或者累了的时候,视频是个不错的选择
在这里,最后只一句话:祝大家offer拿到手软!!