文章目录
- 1 题目理解
- 2 回溯
- 90 subset II
- 方式一代码
- 方式三代码
1 题目理解
Given an integer array nums, return all possible subsets (the power set).
The solution set must not contain duplicate subsets.
输入:int数组nums
输出:返回所有可能的子数组,不能重复
例如
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
2 回溯
子数组中可能不包含任意一个元素,子数组的长度可能是0,1,2…n。我们可以对长度为1的子数组先做回溯,再对长度为2的子数组做回溯。
子数组长度为k的时候,第0位可能是从0到n选择一个数,第1位可能是从上一步选择的位置到n选择一个数。
例如k=2,
第0位,从0到n选择一个,如果选择1,进入状态dfs(2,1)
第1位的时候,从2到n选择一个,如果选择3,进入状态dfs(4,0)
这时候2个数都已经选好了,将组合填入到结果集
class Solution {private List<List<Integer>> answer;private int[] nums;public List<List<Integer>> subsets(int[] nums) {answer = new ArrayList<List<Integer>>();int n = nums.length;this.nums = nums;answer.add(new ArrayList<Integer>());for(int i=1;i<=n;i++){dfs(0,i, new ArrayList<Integer>());}return answer;}private void dfs(int index,int k,List<Integer> list){if(k==0){answer.add(new ArrayList<Integer>(list));return;}if(index>=nums.length) return ;for(int i=index;i<nums.length;i++){list.add(nums[i]);dfs(i+1,k-1,list);list.remove(list.size()-1);}}
}
还有一种思路是,每个元素可能选择也可能不选择。对每个元素进行回溯。
class Solution {private List<List<Integer>> answer;private int[] nums;public List<List<Integer>> subsets(int[] nums) {answer = new ArrayList<List<Integer>>();int n = nums.length;this.nums = nums;dfs(0,new ArrayList<Integer>());return answer;}private void dfs(int index,List<Integer> list){if(index>=nums.length){answer.add(new ArrayList<Integer>(list));return;}list.add(nums[index]);dfs(index+1,list);list.remove(list.size()-1);dfs(index+1,list);}
}
这种思路还有一种二进制的写法。因为每个元素选择不选择,可以用二进制位表示。数组长度为n,那么可以表示的数就是[0,2n−1][0,2^n-1][0,2n−1]。
class Solution {public List<List<Integer>> subsets(int[] nums) {List<List<Integer>> answer = new ArrayList<List<Integer>>();int n = nums.length;int max = (1<<n)-1;for(int i=0;i<=max;i++){List<Integer> list = new ArrayList<Integer>();for(int j=0;j<n;j++){if(((i>>j) &1)==1 ){list.add(nums[j]);}}answer.add(list);}return answer;}
}
90 subset II
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: [1,2,2]
Output:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
同样是找子数组。这次nums可能包含重复元素。在有重复元素做选择的时候,相同元素,就要选择第一个,第一个不选择,第二个也不能选择。例如[8,8],可以两个都不选择;也可以选择第1个8,不选择第2个8;也可以选择第1个8,第2个8。但是不选择第1个8,选择第2个8,就会出现重复,不能这样选。
可以采取的方式有三种。一种是先对数组排序。排序之后,在不选择某个元素的时候,状态转移的时候要找到下一个不等于当前元素的数。这种方式在40. Combination Sum II 遇到过。
第二种采取计数的方式,提前计算好每个元素可以使用的次数。这种方式写代码不太好处理,忽略。
第三种是用一个数组记录是否使用了某个元素。在和前一个元素值相同的时候,前一个元素不使用,第二个元素也不使用。
方式一代码
class Solution {private List<List<Integer>> answer;private int[] nums;public List<List<Integer>> subsetsWithDup(int[] nums) {answer = new ArrayList<List<Integer>>();int n = nums.length;this.nums = nums;Arrays.sort(nums);dfs(0,new ArrayList<Integer>());return answer;}private void dfs(int index,List<Integer> list){if(index>=nums.length){answer.add(new ArrayList<Integer>(list));return;}list.add(nums[index]);dfs(index+1,list);list.remove(list.size()-1);while(index+1<nums.length && nums[index+1]==nums[index]) index++;dfs(index+1,list);}
}
方式三代码
class Solution {private List<List<Integer>> answer;private int[] nums;private boolean[] visited;public List<List<Integer>> subsetsWithDup(int[] nums) {answer = new ArrayList<List<Integer>>();int n = nums.length;this.nums = nums;visited = new boolean[n];Arrays.sort(nums);dfs(0,new ArrayList<Integer>());return answer;}private void dfs(int index,List<Integer> list){if(index>=nums.length){answer.add(new ArrayList<Integer>(list));return;}if(!(index>0 && nums[index]==nums[index-1] && !visited[index-1])){list.add(nums[index]);visited[index]=true;dfs(index+1,list);list.remove(list.size()-1);visited[index]=false;}dfs(index+1,list);}
}