## 子集系列(一) 传统subset 问题，例 [LeetCode] Subset, Subset II, Bloomberg 的一道面试题

### 引言

Coding 问题中有时会出现这样的问题：给定一个集合，求出这个集合所有的子集(所谓子集，就是包含原集合中的一部分元素的集合)。

### 例题1, 不包含重复元素的集合S，求其所有子集

Given a set of distinct integers, 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,3], a solution is:

[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
class Solution {
public:
vector<vector<int> > subsets(vector<int> &S) {
}
};

class Solution {
public:
vector<vector<int> > subsets(vector<int> &S) {
vector<vector<int> > res;
vector<int> emp;
res.push_back(emp);
sort(S.begin(), S.end());
if(S.size() == 0) return res;
for(vector<int>::iterator ind = S.begin(); ind < S.end(); ++ind){
int size = res.size();
for(int i = 0; i < size; ++i){
vector<int> v;
for(vector<int>::iterator j = res[i].begin(); j < res[i].end(); ++j){
v.push_back(*j);
}
v.push_back(*ind);
res.push_back(v);
}
}
return res;
}
};

10 / 10 test cases passed. Runtime: 16 ms

class Solution {
public:
vector<vector<int> > subsets(vector<int> &S) {
vector<int> v;
sort(S.begin(), S.end());
subsetsCore(S, 0, v);
return res;
}
private:
vector<vector<int> > res;
void subsetsCore(vector<int> &S, int start, vector<int> &v){
if(start == S.size()) { res.push_back(v); return;}
vector<int> v2;
for(vector<int>::iterator i = v.begin(); i < v.end(); v2.push_back(*(i++)));
v.push_back(S[start]);
subsetsCore(S, start+1, v); //包含S[start]
subsetsCore(S, start+1, v2); //不包含S[start]
}
};

10 / 10 test cases passed. Runtime: 40 ms

### 例题2，S中包含有重复元素

Subsets II

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.

class Solution {
public:
vector<vector<int> > subsetsWithDup(vector<int> &S) {
vector<vector<int> > subsets;
vector<int> v;
subsets.push_back(v);
if(S.empty()) return subsets;
sort(S.begin(), S.end());
int m = 0; //m 用来存储上一次加进来的子集们的起始index
for(vector<int>::iterator i = S.begin(); i < S.end(); ++i){
int start = ((i != S.begin() && *i == *(i-1)) ? m : 0); //如果S的当前元素和前一个元素相同，只拷贝上次加进来的子集
int end = subsets.size();
for(int j = start; j < end; ++j){
vector<int> vt;
for(vector<int>::iterator k = subsets[j].begin(); k < subsets[j].end(); ++k){
vt.push_back(*k);
}
vt.push_back(*i);
subsets.push_back(vt);
}
m = end;
}
return subsets;
}
};

19 / 19 test cases passed，Runtime: 72 ms

class Solution {
public:
vector<vector<int> > subsetsWithDup(vector<int> &S) {
vector<int> v;
sort(S.begin(), S.end());
subsetsCore(S, 0, v);
return res;
}
private:
vector<vector<int> > res;
void subsetsCore(vector<int> &S, int start, vector<int> &v){
if(start == S.size()) { res.push_back(v); return;}
if(v.size() == 0 || v[v.size()-1] != S[start]){    //When S[start] != v[v.size()-1], we need to consider both case: add S[start] into v; not add S[start] to v. If S[start] == v[v.size()-1], we only need to consider the case add S[start] into v.
vector<int> v2;
for(vector<int>::iterator i = v.begin(); i < v.end(); v2.push_back(*(i++)));
subsetsCore(S, start+1, v2);
}
v.push_back(S[start]);
subsetsCore(S, start+1, v);
}
};

19 / 19 test cases passed，Runtime: 52 ms

class Solution {
public:
vector<vector<int> > subsetsWithDup(vector<int> &S) {
sort(S.begin(), S.end());
subsetsCore(S, 0);
return res;
}
private:
vector<int> path;
vector<vector<int> > res;
void subsetsCore(vector<int> &S, int start){
if(start == S.size()) { res.push_back(path); return;}
if(path.size() == 0 || path[path.size()-1] != S[start])
subsetsCore(S, start+1);    //When S[start] != v[v.size()-1], we need to consider both case: add S[start] into v; not add S[start] to v. If S[start] == v[v.size()-1], we only need to consider the case add S[start] into v.
path.push_back(S[start]);
subsetsCore(S, start+1);
path.pop_back();
}
};

19 / 19 test cases passed，Runtime: 48 ms

### 例题3，string 的子集

void subsets(string s) {
if(s.length() == 0) return;
unsigned int i = 1, judgeEnd = (1 << s.length()) - 1; //judgeEnd用来判定i 递增的终止
int j = 0;
for(; (i & judgeEnd) > 0; cout << endl, ++i){
for(mask = 1 << (s.length() - 1), j = 0; j < s.length(); ++j, mask = mask >> 1){
if(mask & i) cout << s[j];
}
}
}

posted on 2014-06-08 07:36  Felix Fang  阅读(11137)  评论(0编辑  收藏  举报