给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
这道题并没有什么新的知识点,就是78.子集与40.组合总和Ⅱ结合一下。重新整理一下树枝去重和树层去重(result数组中没有相同的集合)
过程图来自代码随想录:
![](https://i-blog.csdnimg.cn/blog_migrate/2f53a4bf817679d32d6798f86dd54ae4.png)
1.树枝去重:保证list集合(result中元素)中没有重复元素,list集合元素的收集来自递归,伴随着每次递归startIndex的增加,list数组被构建。这道题目并没有要求list数组中不能有重复元素,因为list数组中的重复元素有可能是两个不同位置,但数值相同的元素。
2.保证result中没有重复元素就要树层去重,并且要提前对要操作的数组进行升序排列(保证相同数字挨在一块)当我们发现数组相邻的两个元素相等,并且前一个元素已经被访问,那么我们就直接跳过当前元素的递归遍历,由于前一个元素与当前的元素相等,以前一个元素开头的所有遍历情况包含以了当前元素开头的所有情况,继续遍历的话就会和result中已经存在的元素重复。
Java代码:
class Solution {
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> list = new ArrayList<Integer>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
boolean[] visited = new boolean[nums.length];
backtracking(nums,0,visited);
return result;
}
public void backtracking(int[] nums,int startIndex,boolean[] visited){
//求子集,不需要判断result的收集条件,直接收集所有情况就行
result.add(new ArrayList<Integer>(list));
if(startIndex >= nums.length){
return;
}
for(int i = startIndex; i < nums.length; i++){
//去重
if(i > 0 && nums[i - 1] == nums[i] && !visited[i - 1]){
continue;
}
//及那个当前元素标记为已经访问
visited[i] = true;
list.add(nums[i]);
backtracking(nums,i + 1,visited);
list.remove(list.size() - 1);
visited[i] = false;
}
}
}
为什么要用!visited[i - 1]来当做去重条件,要注意我们要实现result中没有重复元素,就要进行树层去重,进行树层去重都是在每一层的第一个节点往后的每一个节点进行去重,而这些节点都是经过了回溯的,在回溯的过程中我们已经将当前节点的前一个节点设为false了。