法1:回溯
同46. 全排列 - 力扣(LeetCode)差不多,也是用回溯优化遍历,甚至更简单
class Solution {
List<List<Integer>> ans = null;
int[] nums = null;
int n = 0;
public List<List<Integer>> subsets(int[] nums) {
ans = new ArrayList<List<Integer>>();
this.nums = nums;
this.n = nums.length;
backTrack(0, new ArrayList<Integer>());
return ans;
}
//idx表示当前遍历到数组nums的下标
public void backTrack(int idx, List<Integer> list) {
if(idx == n) {
ans.add(new ArrayList<>(list));
return;
}
//选择该元素
list.add(nums[idx]);
backTrack(idx + 1, list);
//回溯
list.remove(list.size() - 1);
//不选择该元素
backTrack(idx + 1, list);
}
}
法2:二进制枚举(迭代)
这道题,也可以通过迭代,不用递归完成。子集嘛,种可能,对于子集是否选择每个元素正好可以用一个bit表示,那么子集的情况,可以用 0(00...0 , n个0) ,1(00...0001), ...,
-1( 11...1,n个1)这些二进制数表示是否选择某个元素。
然后判断某个具体元素是否被选择,就通过移位 与 &运算来判断。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
int n = nums.length;
int total = 1 << n;//表示2的n次方
for(int i=0;i<total;i++) {
List<Integer> list = new ArrayList<>();
for(int j=0;j<n;j++) {
//j下标这个是否被选择
if(((i >>> j) & 1) == 1)
list.add(nums[j]);
}
ans.add(list);
}
return ans;
}
}