Subsets II -- leetcode

来源:互联网 发布:手机淘宝关注是收藏吗 编辑:程序博客网 时间:2024/05/02 04:57

Given a collection of integers that might contain duplicates, S, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If S = [1,2,2], a solution is:

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


算法一,递归回溯

首先进行排序。

第一层底归,完成长度为1的所有子集

第二层底归,完成长度为2的所有子集

。。。

在每层递归中,依次添加剩余字符的组合。遇到重复字符,则跳过。

在leetcode上实际执行时间为13ms。

class Solution {public:    vector<vector<int> > subsetsWithDup(vector<int> &S) {        sort(S.begin(), S.end());        vector<vector<int> >ans(1);        vector<int> sample;        helper(ans, S, 0, sample);        return ans;    }        void helper(vector<vector<int> > &ans, const vector<int> &S, int start, vector<int> &sample) {        if (start == S.size()) return;                for (int i=start; i<S.size(); i++) {            sample.push_back(S[i]);            ans.push_back(sample);            helper(ans, S, i+1, sample);            sample.pop_back();            while (i+1 < S.size() && S[i] == S[i+1]) i++;        }    }};


算法二  统计重复数字个数

如果不考虑重复数字,那么总的子集数,应该是2^n。

即,对于每个一字符,都有2种情况共选择,放入子集,或者不放入子集。故是2^n个子集。

对于重复数字的情况,可以把他们当成一个整体来考虑。

假设一个数字重复3次,那么对于这个特殊整体,就会有4种情况, 即, 不放入,放入1个,放入2个,放入3个。

同理,对于重复次数为n, 就有n+1种情况。


下面代码,也有DP的意味, 即已经知道n-1个字符的子集全集,求了n个字符的子集全集。

先统计出第n个字符的重复次数。

在已有的集合中,对每个子集,进行上面描述的放入操作。

下列代码,在leetcode上实际执行时间为15ms。

class Solution {public:    vector<vector<int> > subsetsWithDup(vector<int> &S) {        sort(S.begin(), S.end());        vector<vector<int> >ans(1);        for (int i=0; i<S.size(); i++) {            int count = 1;            while (i+1 < S.size() && S[i] == S[i+1]) {                count++;                i++;            }                        const int size = ans.size();            for (int j=0; j<size; j++) {                ans.push_back(ans[j]);                ans.back().push_back(S[i]);                for (int k=1; k<count; k++) {                    ans.push_back(ans.back());                    ans.back().push_back(S[i]);                }            }        }                return ans;    }};

该算法思路参考自:

https://leetcode.com/discuss/14902/c-solution-and-explanation



算法三 逐个字符添加

这个思路也类似于DP。

已知n-1个字符的子集的全集,求n个字符的子集的全集。

方法是,对已有的每个子集,复制一份,并添加该新字符。

对于后续重复的字符, 则只复制上次新增子集,并添加该字符。

本代码,在leetcode上实际执行时间为14ms。

class Solution {public:    vector<vector<int> > subsetsWithDup(vector<int> &S) {        sort(S.begin(), S.end());        vector<vector<int> >ans(1);        int last_size = 0;        for (int i=0; i<S.size(); i++) {            const int start = i && S[i]==S[i-1] ? last_size : 0;            last_size = ans.size();            for (int j=start; j<last_size; j++) {                ans.push_back(ans[j]);                ans.back().push_back(S[i]);            }        }        return ans;    }};


该算法参考自:

https://leetcode.com/discuss/11905/simple-iterative-solution

0 0
原创粉丝点击