题目如下:
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;
}
};