【LeetCode】95. Subsets II

题目描述(Medium)

Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

题目链接

https://leetcode.com/problems/subsets-ii/description/

Example 1:

Input: [1,2,2]
Output:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

算法分析

方法一:dfs解法,时间复杂度O(2^n),空间复杂度O(n),注意到处理第三个元素2时,因为前面已经处理了一次2,所有第三层中,我们只在已经添加过2的集合{1,2}、{2}上再添加2,而没有在集合{1}, {}上添加2(画叉的分支),假设下面还有一个2,那么我们只在第四层的包含两个2的集合{1,2,2}、{2,2}上再添加2,其它都不添加。因此dfs时,如果当前处理的数字前面出现了k次,那么我们要处理的集合中必须包含k个该元素。

方法二:如果当前处理的元素没有出现过,则把前面得到的所有集合加上该元素;如果出现过,则只把上一轮处理的集合加上该元素。比如处理第二个2时(二叉树第三层),我们只把上一轮添加过数字的集合{1,2}、{2}再添加一个2加入结果中,{1}、{}是从上一层直接继承下来的,所以不作处理。时间复杂度O(2^n),空间复杂度O(1)

扫描二维码关注公众号,回复: 3741726 查看本文章

算法参考自:LeetCode:Subsets I II

提交代码(方法一):

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<int> path;
        vector<vector<int>> result;
        dfs(nums, path, 0, result);
        return result;
    }
    
    void dfs(vector<int>& nums, vector<int>& path, 
                 int step, vector<vector<int>> &result) {
        if (step == nums.size())
        {
            result.push_back(path);
            return;
        }
        int firstSame = step;
        while (firstSame >= 0 && nums[step] == nums[firstSame])
            --firstSame;
        int sameNum = step - firstSame - 1;
        if (sameNum == 0 || (path.size() >= sameNum 
                             && path[path.size()- sameNum] == nums[step])) {
            // 考虑S[i]
            path.push_back(nums[step]);
            dfs(nums, path, step + 1, result);
            path.pop_back(); 
        }
        // 不考虑S[i]
        dfs(nums, path, step + 1, result);
    }

};

提交代码(方法二):

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        result.push_back(vector<int>());
        
        int last = nums[0], opResNum = 1;
        for (int i = 0; i < nums.size(); ++i) {
            
            // 保留当前操作增加的子集数目
            if (nums[i] != last)
            {
                last = nums[i];
                // 此时集合数目,保留到下一次做差
                opResNum = result.size();
            }
            
            int prev_size = result.size() - opResNum;
            for (int j = result.size() - 1; j >= prev_size; --j) {
                result.push_back(result[j]);
                result.back().push_back(nums[i]);
            }
        }
        
        return result;
    }
};

猜你喜欢

转载自blog.csdn.net/ansizhong9191/article/details/83022924
今日推荐