给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: [1,2,2]

输出:

[

  [2],

  [1],

  [1,2,2],

  [2,2],

  [1,2],

  []

]

答案:

 1public List<List<Integer>> subsetsWithDup1(int[] nums) {
2    Arrays.sort(nums);
3    List<List<Integer>> list = new LinkedList<>();
4    backtrack(nums, listnew LinkedList<Integer>(), 0);
5    return list;
6}
7
8private void backtrack(int[] nums, List<List<Integer>> listList<Integer> tempList, int level) {
9    list.add(new LinkedList<>(tempList));
10    for (int i = level; i < nums.length; i++) {
11        if (i != level && i > 0 && nums[i] == nums[i - 1])
12            continue;
13        tempList.add(nums[i]);
14        backtrack(nums, list, tempList, i + 1);
15        tempList.remove(tempList.size() - 1);
16    }
17}

解析:

这题和241,子集有异曲同工之妙。主要还是递归和回溯的思想,每个元素都有选和不选两种情况,并且有重复的元素出现,我们必须要去重。怎么描述呢,我举个例子吧,比如【1,2,3,3,4,5】,当前面1,2组成的集合list和第一个3结合的时候有选和不选两种情况,选的时候即list+3+rest,不选的时候即list+""+rest。当遇到第二个3的时候也有选和不选两种情况,选的时候即list+3+3+rest和list+""+3+rest。不选的时候即list+3+""+rest和list+""+""+rest。所以list+""+3+restlist+3+""+rest出现了重复。可能有些同学会说,如果去重之后是不是list+3+3+rest这种情况就不会出现了,这里完全不用担心,关键在i!=level这行代码。这题和241题一样解法都非常多,就不再过多介绍,下面再来看最后一种解法。

 1public List<List<Integer>> subsetsWithDup2(int[] num) {
2    Arrays.sort(num);
3    List<List<Integer>> ret = new ArrayList<>();
4    ret.add(new ArrayList<>());
5    int size = 0, startIndex;
6    for (int i = 0; i < num.length; i++) {
7        startIndex = (i >= 1 && num[i] == num[i - 1]) ? size : 0;
8        size = ret.size();
9        for (int j = startIndex; j < size; j++) {
10            List<Integer> temp = new ArrayList<>(ret.get(j));
11            temp.add(num[i]);
12            ret.add(temp);
13        }
14    }
15    return ret;
16}

这个也很好理解,他会把前面已经组成的大的集合中的小集合一个个取出来再添加上当前的元素最后再放进原来的大集合中。