2021-11-6 90. 子集 II(回溯+去重)

这篇博客探讨了如何使用回溯算法解决含有重复元素的子集问题。通过对比78号题目的子集问题,作者指出关键在于处理同一树层和树枝上的重复元素。文章提供了一个解决方案,对输入数组进行排序,并在回溯过程中避免重复子集的生成。时间复杂度为O(n×2^n),空间复杂度为O(n)。
摘要由CSDN通过智能技术生成

注:

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

题解:
思路
做本题之前一定要先做78.子集 (opens new window)。

这道题目和leetcode 78的区别就是集合里有重复元素了,而且求取的子集要去重。

那么关于回溯算法中的去重问题,在40.组合总和II (opens new window)中已经详细讲解过了,和本题是一个套路。

剧透一下,后期要讲解的排列问题里去重也是这个套路,所以理解树层去重树枝去重非常重要。

用示例中的[1, 2, 2] 来举例,如图所示: (注意去重需要先对集合排序)

在这里插入图片描述

从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集

复杂度分析
时间复杂度:O(n×2n),其中 n 是数组 nums 的长度。排序的时间复杂度为 O(nlogn)。最坏情况下 nums 中无重复元素,需要枚举其所有 2n 个子集,每个子集加入答案时需要拷贝一份,耗时 O(n),一共需要 O(n×2n)+O(n)=O(n×2n) 的时间来构造子集。由于在渐进意义上 O(nlogn) 小于 O(n×2n),故总的时间复杂度为 O(n×2n)。

空间复杂度:O(n)。临时数组 t 的空间代价是 O(n),递归时栈空间的代价为 O(n)。

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums,vector<int>& visited,int index ){
        if(index>nums.size()){
            return ;
        }
        for(int i=index;i<nums.size();i++){
            // visited[i - 1] == 1,说明同一树枝candidates[i - 1]使用过
            // visited[i - 1] == 0,说明同一树层candidates[i - 1]使用过
            if(i>=1&&nums[i-1]==nums[i]&&visited[i-1]==0){
                continue;
            }
            visited[i]=1;
            path.push_back(nums[i]);
            result.push_back(path);
            backtracking(nums,visited,i+1);
            path.pop_back();
            visited[i]=0;
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<int> visited(nums.size(),0);
        sort(nums.begin(),nums.end());
        result.push_back(path);
        backtracking(nums,visited,0);
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值