给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
方法一 位运算
可以使用0-1序列来表示每个子集,0表示不包含此元素,1表示包含此元素。
例如:
[1] -> 100
[1, 2] -> 110
[1, 2, 3] -> 111
而一个包含n个元素的集合,其子集个数为2^n正好对应000~111
class Solution {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> sub = new ArrayList<Integer>();
public List<List<Integer>> subsets(int[] nums) {
for(int i = 0; i < (1 << nums.length); i++) { // 循环2^n次 表示所有子集的0-1序列
sub.clear(); // 获取子集前清空
for (int j = 0; j < nums.length; j++) // 相当于用 001 010 100 这样的单个元素去检测
if ((i & (1 << j)) != 0) // 不为1则nums[j]在这个子集中
sub.add(nums[j]);
res.add(new ArrayList<Integer>(sub)); // 一定要new新的对象 不然每个元素都指向同一内存空间
}
return res;
}
}
方法二 回溯法
dfs(pos, n) 表示 pos:当前处理元素的位置 n:元素总数
重点理解:
1.当进行到dfs(pos, n)时:①[0, pos-1]已经确定 ②[pos, n)未确定 ③正在确定pos
2.确定pos位置有两个行为:①选取 ②不选取
3.①选取 -> 将其add到列表中 ②不选取 -> remove列表末尾的元素
class Solution {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> sub = new ArrayList<Integer>();
private void dfs(int pos, int[] nums) {
if (pos == nums.length){
res.add(new ArrayList<Integer>(sub));
return;
}
sub.add(nums[pos]); // 取->添加这个位置的元素
dfs(pos + 1, nums); // 递归下一个位置
sub.remove(sub.size()-1); // 不取->回溯!
dfs(pos + 1, nums); // 递归下一个位置
}
public List<List<Integer>> subsets(int[] nums) {
dfs(0, nums);
return res;
}
}