题目如下:
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],
[]
]
分析如下:
和上一题基本一样,区别在于这道题目的输入集合中的元素可能有重复,要求输出的子集合中过滤掉重复。可以先得到一个有重复的结果,再用个set或者hash滤重(使用0(N)空间复杂度)
我的代码:
第一版本,先迭代再滤重版本
// 先迭代再滤重 class Solution { public: vector<vector<int> > subsetsWithDup(vector<int> &S) { int length=(int)S.size(); vector<vector<int>> res(1); if(length==0) return res; std::sort(S.begin(), S.end()); for(int i=0;i<S.size();++i){ int j=(int)res.size(); while(--j>=0){ res.push_back(res[j]); res.back().push_back(S[i]); } } set<vector<int> > filter_set; for(int i=0;i<res.size();++i) filter_set.insert(res[i]); res.clear(); for(set<vector<int> >::iterator it=filter_set.begin();it!=filter_set.end();it++) res.push_back(*it); return res; } };
第二版本,先递归再滤重版本
//先递归再滤重 class Solution { public: set<vector<int> > subsets_(vector<int> &S, int i){ if(i==-1){ vector<int> set_tmp; set<vector<int> > set_set_tmp; set_set_tmp.insert(set_tmp); return set_set_tmp; } set<vector<int> > set_vec_tmp = subsets_(S,i-1); set<vector<int> > set_vec_out = set_vec_tmp; set<vector<int> >::iterator set_vec_it=set_vec_tmp.begin(); for(set_vec_it=set_vec_tmp.begin();set_vec_it!=set_vec_tmp.end();set_vec_it++){ vector<int> vec_tmp=*set_vec_it; vec_tmp.push_back(S[i]); std::sort(vec_tmp.begin(),vec_tmp.end()); set_vec_out.insert(vec_tmp); } return set_vec_out; } vector<vector<int> > subsetsWithDup(vector<int> &S) { int length=(int)S.size(); vector<vector<int>> res; set<vector<int>> tmp; if(length==0) return res; length--; tmp=subsets_(S,length); for(set<vector<int> >::iterator it=tmp.begin();it!=tmp.end();it++){ vector<int> small_vec=*it; res.push_back(small_vec); } return res; } };
第三版本
我还没怎么看懂,不使用set不使用hash直接滤重,官网上看到的答案如下。
//不使用set或者hash直接滤重 class Solution { public: vector<vector<int> > subsetsWithDup(vector<int> &S) { // Start typing your C/C++ solution below // DO NOT write int main() function vector<int> path; vector<vector<int> > result; sort(S.begin(), S.end()); sub(S, 0, path, result); return result; } void sub(vector<int> &s, int begin, vector<int> &path, vector<vector<int> > &result) { result.push_back(path); for (int i = begin; i < s.size(); ++i) { if (i != begin && s[i] == s[i - 1]) continue; path.push_back(s[i]); sub(s, i + 1, path, result); path.pop_back(); } } };
参考资料:
(1) http://discuss.leetcode.com/questions/253/subsets
update: 2014 - 12 - 17
在LeetCode(79) Subset 的不含重复元素的迭代版的思路上,回顾思路如下:
题目: If S = [1,2,3], return a solution of:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
首先对S进行排序。
接下来进行subset的生成。
初始状态: []
第0次,加入S[0], 得到: [], [1]
第1次,加入S[1], 得到: [], [1], [2], [1, 2]
第2次,加入S[2], 得到: [], [1], [2], [1, 2], [3], [1,3], [2,3], [1,2,3]
从上面可以看出,
第0次->第1次,把S[1]加入到S[0]的每个subset中,形成新的subset(即[2], [1, 2]), 然后这堆新的subset和之前S[0]时候的那堆老的subset(即[], [1])一起构成新的结果(即 [], [1], [2], [1, 2])。
第1次->第2次,把S[2]加入到S[1]的每个subset中,形成新的subset(即[3], [1,3], [2,3], [1,2,3]), 然后这堆新的subset和之前S[1]时候的那堆老的subset(即[], [1], [2], [1,2])一起构成新的结果(即 [], [1], [2], [1, 2], [3], [1,3], [2,3], [1,2,3] )。
如果输入字符串S为长度更长的字符串,则重复上面这个过程直到把S的每个元素都加入了当前的集合。
然后,再看重复版本的迭代版本。
If S = [1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
首先对S进行排序。
接下来进行subset的生成。
第0次,填入S[0], 得到: [], [1]
第1次,填入S[1], 得到: [], [1], [2], [1,2]
第2次,填入S[2], 得到: [], [1], [2], [1,2], [2,2], [1,2,2]
可以看出来,在有重复输入的情况下,
第0次,因为没有重复输入,所以情况和没有重复版本的情况一样。
第1次,因为没有重复输入,所以情况和没有重复版本的情况一样。
第2次,因为有了重复输入(第2次的S[2] = 第1次的S[1] = 2),所以新生成的部分(第2次的绿色)只能从第1次的新生成部分(第1次的红色)产生,不能从第0次的产生。
下面,用this_layer记录当前这次的生成部分,这样,如果下次出现重复输入,就使用this_layer来生成新的部分。
class Solution { public: vector<vector<int> > subsetsWithDup(vector<int> &S) { std::sort(S.begin(), S.end()); vector<vector<int> > final(1); vector<vector<int> > this_layer; vector<int> every; int len = 0; for (int i = 0; i < S.size(); ++i) { if (i>0 && S[i] == S[i-1]) { vector<vector<int> > this_layer_swap; for (int j = 0; j < this_layer.size(); ++j) { every = this_layer[j]; every.push_back(S[i]); final.push_back(every); this_layer_swap.push_back(every); } this_layer = this_layer_swap; } else { len = final.size(); this_layer.clear(); for (int j = 0; j < len; ++j) { every = final[j]; every.push_back(S[i]); final.push_back(every); this_layer.push_back(every); } } } return final; } };
update: 2015-03-24 删除了一个不必要的中间变量 vector<int> final.
//14ms class Solution { public: vector<vector<int> > subsetsWithDup(vector<int> &S) { std::sort(S.begin(), S.end()); vector<vector<int> > final(1); vector<vector<int> > this_layer; vector<vector<int> > next_layer; int len = 0; for (int i = 0; i < S.size(); ++i) { if (i>0 && S[i] == S[i-1]) { next_layer.clear(); for (int j = 0; j < this_layer.size(); ++j) { final.push_back(this_layer[j]); final.back().push_back(S[i]); next_layer.push_back(final.back()); } this_layer.swap(next_layer); } else { len = final.size(); this_layer.clear(); for (int j = 0; j < len; ++j) { final.push_back(final[j]); final.back().push_back(S[i]); this_layer.push_back(final.back()); } } } return final; } };