90.子集II

目标

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

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

说明:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

思路

返回数组不重复的子序列。

枚举子序列可以使用迭代或者回溯。迭代的思路是使用 bitmap 表示对应下标是否在子序列中,如果数组中元素个数为 nbitmap 值为 1 << n。回溯的思路是当前元素选或者不选,或者从当前元素到结尾下一个元素选哪一个。

题目的关键是如何判断收集到的子序列是否重复,这里的重复指组成子序列的元素与个数完全相同。

很容易想到使用序列的字符串来判断是否重复,但是如何处理组成元素相同而顺序不同的情况?可以对原数组排序,这样可以保证相同元素在子序列中的出现位置相同。比如 4, 4, 4, 1, 4,排序后 4 只会出现在 1 的后面,如果子序列中 4 的个数相同,那么子序列字符串也相同,这样就可以去重了。

如果使用回溯,则可以在枚举时直接去重。如果不选择某个元素,那么后面 相同的 元素都不选。这样可以保证相同元素同样的出现次数只枚举一次。

也有网友使用桶排序,回溯时对相同元素枚举取 0 ~ k 个。

代码


/**
 * @date 2025-02-05 9:09
 */
public class SubsetsWithDup90 {

    public List<List<Integer>> subsetsWithDup_v1(int[] nums) {
        int n = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        Set<String> set = new HashSet<>();
        Arrays.sort(nums);
        n = 1 << n;
        for (int i = 0; i < n; i++) {
            List<Integer> subset = new ArrayList<>();
            for (int j = 0; j < nums.length; j++) {
                if (((i >> j) & 1) == 1) {
                    subset.add(nums[j]);
                }
            }
            if (!set.contains(subset.toString())) {
                res.add(subset);
            }
            set.add(subset.toString());
        }
        return res;
    }

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        List<Integer> subset = new ArrayList<>();
        dfs(0, nums, subset, res);
        return res;
    }

    public void dfs(int index, int[] nums, List<Integer> subset, List<List<Integer>> res) {
        if (index == nums.length) {
            res.add(new ArrayList<>(subset));
            return;
        }
        subset.add(nums[index]);
        dfs(index + 1, nums, subset, res);
        subset.remove(subset.size() - 1);
        index++;
        while (index < nums.length && nums[index] == nums[index - 1]){
            index++;
        }
        dfs(index, nums, subset, res);
    }

}

性能

bitmap 迭代

回溯