-
思路一:回溯
- 对于这种可以分为若干步,每一步有很多选择的题目非常适合用回溯法来做。
- 具体的方式为写一个helper函数,参数为当前的结果集合subset,当前选择的数字的索引index。
- 首先需要判断,如果index和nums.length相等时说明所有的元素都考虑过了,那么就把现在的结果集合加入到result中(注意要new一个新的List)
- 当index < nums.length时说明此时正在选择某一个元素。对于这个元素我们可以不选择它,那么就直接调用helper函数,那么此时选择的是下一个元素,所以参数是index+1。当然我们也可以选择这个元素,那么就先把数字加入到subset中,然后再调用helper函数,最后从递归状态树中返回父节点时要清除当前状态,所以最后还要把该数字从列表中删除
class Solution { List<List<Integer>> result; int[] nums; public List<List<Integer>> subsets(int[] nums) { result = new ArrayList<>(); this.nums = nums; helper(new ArrayList<Integer>(), 0); return result; } private void helper(List<Integer> subset, int index) { if (index == nums.length) result.add(new LinkedList<>(subset)); else { // 不选择这个数 helper(subset, index + 1); // 选择这个数 subset.add(nums[index]); helper(subset, index + 1); subset.remove(subset.size() - 1); } } }
-
思路二:二进制枚举
- 以三个数字为例,子集共有2^3个。对于每个数字的选择与否我们可以看作二进制的某一位是1还是0.因此长度为n的数组对应的状态数目可以用n位二进制数来代表。具体得到某个数字后,我们分别得到每一位的值,判断是1还是0,如果是1就把对应的数字加入当前的subset
class Solution { public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < (1 << nums.length); i++) { List<Integer> subset = new ArrayList<>(); for (int j = 0; j < nums.length; j++) { if (1 == ((i >> j) & 1)) subset.add(nums[j]); } result.add(subset); } return result; } }
11-17
234
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
04-26
140
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)