Given a collection of integers that might contain duplicates, S, return all possible subsets.
Note:
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原文地址:http://blog.csdn.net/elton_xiao/article/details/45291043