第一次遇到子集问题
子集问题某种程度上和组合问题类似 是无序的
其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,
那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
backtracking(nums, 0);
return res;
}
private void backtracking(int[] nums, int startIndex){
res.add(new ArrayList<>(path));
if(startIndex >= nums.length){
return;
}
for(int i = startIndex; i < nums.length; i++){
path.add(nums[i]);
backtracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
}
这题涉及到去重的逻辑
还是一样 子集问题 是收集递归树的所有节点
那么关于回溯算法中的去重问题,在40.组合总和II (opens new window)中已经详细讲解过了,和本题是一个套路。
剧透一下,后期要讲解的排列问题里去重也是这个套路,所以理解“树层去重”和“树枝去重”非常重要。
同一层不能重复取 但是 同一树枝可以重复取
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
backtracking(nums, 0);
return res;
}
private void backtracking(int[] nums, int startIndex){
res.add(new ArrayList<>(path));
if(startIndex >= nums.length){
return;
}
for(int i = startIndex; i < nums.length; i++){
if(i > startIndex && nums[i] == nums[i-1]){
continue;
}
path.add(nums[i]);
backtracking(nums, i+1);
path.remove(path.size() - 1);
}
}
}
也可以使用一个used数组来判断
回溯算法 同一树层的去重逻辑
if (i > startIndex && nums[i] == nums[i - 1] ) {
continue;
}