90. Subsets II

Description:

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.

For example,

If nums = [1,2,2], a solution is:

[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

解析:相比Subsets I,如何避免重复的数字会造成重复的子集是这道题解题的关键。用一个例子来阐述我的思路nums = {1, 2, 2};

  1. 首先一个空集 ret = {{}};
  2. index = 0(属于非重复数字)     将当前状态下的ret先copy一份tmp,在tmp中每一个成员后面添加nums[index], 循环一次后将tmp添加到ret之后;
  3. index = 1(属于重复数字)      index++直到数组结束或者下一个数不相等为止记录下重复数字次数(没有重复的数字次数为1),  然后copy一份ret传给tmp,  循环给tmp的成员后面添加nums[index](数字重复多少次就循环多少次) , 每次循环结束后将tmp添加到ret之后;


             

indexret
0{{}}
1{{}, {1}}
2pass(重复数字为两次)
3{{}{1}{2}{1, 2}{2,2}{1, 2,2}}(tmp后添加2循环两次)

代码1:递归

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        if(nums.empty())    return vector<vector<int> >(1, vector<int>());
        
        sort(nums.begin(), nums.end(), less<int>());
        
        int count = 0;
        int val = nums[0];
        
        while(nums.size() && nums[0] == val)//这里如果不判断nums.size()是否为零的话 会导致越界 出现错误
        {
            nums.erase(nums.begin());
            count++;
        }
        
        vector<vector<int> > ret = subsetsWithDup(nums);
        vector<vector<int> > tmp(ret);
        
        while(count > 0)
        {
            for(auto& i : tmp)
                i.push_back(val);

            ret.insert(ret.end(), tmp.begin(), tmp.end());
            count--;
        }      
        return ret;

    }
};

代码2:尾递归版本(回溯)

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums)
    {
        vector<vector<int>> ret(1, vector<int>());
        sort(nums.begin(), nums.end());
        dfs_subsetsWithDup(nums, ret, 0);
        return ret;
    }
    
    void dfs_subsetsWithDup(vector<int>& nums, vector<vector<int>>& ret, int index)
    {
        if(index == nums.size())    return;
        vector<vector<int> > tmp(ret);
        
        while(index + 1 < nums.size() && nums[index] == nums[index + 1])
        {
            for(auto& r: tmp)
                r.push_back(nums[index]);
            ret.insert(ret.end(), tmp.begin(), tmp.end());
            index++;
        }
        for(auto& r: tmp)
            r.push_back(nums[index]);
        ret.insert(ret.end(), tmp.begin(), tmp.end());

        dfs_subsetsWithDup(nums, ret, index + 1);
    }   
};

代码3:迭代版本


class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums)
    {
        vector<vector<int>> ret(1, vector<int>());
        vector<vector<int>> tmp;
        sort(nums.begin(), nums.end());
        
        for(int i = 0, count = 1; i < nums.size(); i++, count++)
        {
            while(i + 1 < nums.size() && nums[i] == nums[i + 1])
            {
                ++i;
                ++count;
            }
            
            tmp.insert(tmp.end(), ret.begin(), ret.end());
            
            while(count > 0)
            {
                for(auto&t : tmp)
                    t.push_back(nums[i]);
                
                ret.insert(ret.end(), tmp.begin(), tmp.end());
                count--;
            }
            tmp.clear();
        }
        
        return ret;
    }  
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值