算法题分享 | 子集 II

133 阅读3分钟

你值得拥有!!!_3_咕噜噜~_来自小红书网页版.png

题目

给你一个整数数组 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

题解

解题思路

这道题使用迭代或者递归来解决都可以,主要需要实现枚举所有的子集,收集到不重复的子集集合。其中难点在于确保最终的结果中不包含重复的子集。

当数组中有多个相同的元素相邻时,如果一个子集中选择了这些元素中部分元素,并且不是选择靠前的几个,那么这个子集可以跳过不选,因为一定会有跟该子集相同的子集。举个例子,现在有 2,2,2,2 这几个相同的元素并且相邻,此时如果子集中选择了第一和第三的 2,那么最终会和选择第一和第二或者第二和第三等等的子集重复。所以为了防止重复,当要选择若干个相同的元素时,我们可以限定只选择靠前的若干个即可。

因此,落实到具体的做法,我们需要先对数组进行排序,使得相同的元素相邻,然后遍历各子集的每个元素时,都判断是否存在相同并且没有被选中的前一个元素,如果有,就直接跳过该子集。

那如何遍历数组所有的子集呢? 我们可以使用二进制数来表示各个子集,例如对于 3 位的数组,可以使用三位的二进制数表示其子集,例如 010,表示该子集选中第 2 个元素。这样一来,小于 (1 << 3) 的所有数即对应着数组的所有子集。

代码

class Solution {

    List<Integer> cur = new ArrayList<>();
    List<List<Integer>> ans = new ArrayList<List<Integer>>();

    public List<List<Integer>> subsetsWithDup(int[] nums) {

        // 先对 nums 排序,确保相同的元素连续
        Arrays.sort(nums);

        // 数组长度
        int n = nums.length;

        for (int mask = 0; mask < (1 << n); mask++) {
            // 清空 cur
            cur.clear();
            // 记录是否跳过当前子集
            boolean flag = false;
            // 遍历当前子集的元素,添加到 cur 中
            for (int i = 0; i < n; i++) {
                // 通过 mask 判断是否当前子集是否选中当前元素
                if ((mask & (1 << i)) != 0) {
                    // 选中
                    // 前一个元素是否和当前元素相同 && 未被选中
                    if (i > 0 && ((mask & (1 << (i - 1))) == 0) && nums[i] == nums[i - 1]) {
                        flag = true;
                        break;
                    } 
                    cur.add(nums[i]);
                }
            }

            if (!flag) {
                ans.add(new ArrayList(cur));
            }
        
        }

        return ans;
        
    }
}

复杂度分析

  • 时间复杂度:O(n×2ⁿ)
    其中 n 是数组的长度,一共需要枚举 2ⁿ 个子集,每个子集的遍历需要 O(n) 的时间复杂度。
  • 空间复杂度:O(n)
    使用了 cur 集合临时存储子集。

优质项目推荐

推荐一个可用于练手、毕业设计参考、增加简历亮点的项目。

lemon-puls/txing-oj-backend: Txing 在线编程学习平台,集在线做题、编程竞赛、即时通讯、文章创作、视频教程、技术论坛为一体

公众号

有兴趣可以关注公众号一起学习更多的干货哈!

扫码_搜索联合传播样式-白色版.png