「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
前言
力扣第七十八题 子集 如下所示:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入: nums = [1,2,3]
输出: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入: nums = [0]
输出: [[],[0]]
一、思路
题目中有一点很重要:数组中的元素互不相同。只要遍历的过程中不回头,就不会出现重复的问题。
我们的目标是得到所有不重复的子集,既然是所有的可能,那么每个元素都有可能选或者不选,总共有 2^n 次方总可能性。
我们用 0 表示不选, 1 表示选当前位置的元素。以 nums ={1, 2, 3} 作为例子,它们的与二进制对应的关系如下所示:
大致的实现步骤如下:
- 开始遍历,从
0到2^n -1(n为数组nums的长度) - 将遍历的下标转为对应的二进制,并记录结果即可 (例如:当
i=1时,对应的二进制为001,子集的结果为{3}) - 遍历结束,返回所有的子集即可
举个例子
此处以 nums= [1, 2, 3] 作为例子
- 开始遍历,从
i = 0开始 - 当
i = 0时,对应的二进制为000,此时的子集为{} - ......
- 当
i = 7时,对应的二进制为111,此时的子集为{1, 2, 3} - 遍历结束,返回结果集即可
二、实现
实现代码
在将下标转为二进制的过程中,可以直接使用位运算 向右移,这样可以直接判断第几对应的值是否为 1
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> ret = new ArrayList<>();
for (int i = 0; i < (1 << nums.length); i++) {
List<Integer> temp = new ArrayList<>();
for (int j = 0; j < nums.length; j++) {
if ((i >> j & 1) == 1) {
temp.add(nums[j]);
}
}
ret.add(temp);
}
return ret;
}
测试代码
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4};
new Number78().subsets(nums);
}
结果
三、总结
这一题也可以想象成 全二叉树 的遍历,树的深度为 nums.length。从根节点开始,每个节点都可以选择 0 或者 1。
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~