您的位置:首页 > 其它

Subset I & II

2015-09-14 10:42 218 查看
一:subset I

题目:

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],
[]
]

链接:https://leetcode.com/problems/subsets/

分析:说白了就是求不同元素所构成的所有子集,这里提供三种方法

(1)递归————较难理解

对结合[1,2,3] 从0结点的1开始,都有选择或者不选,不选为空,放在左子树,选择放在由子树,这样就得到一棵完全二叉树,其中叶子结点就是我们所求。理解代码可以试着从只有1个结点开始思考。

图中与代码有差异,左右刚好相反



[cpp] view
plaincopyprint?





class Solution {

public:

void recursion(vector<int> temp, vector<int> &S, int level, vector<vector<int> > &result){

if(level == S.size()){

result.push_back(temp);

return;

}

recursion(temp, S, level+1, result); // 不选元素s[level] 通过只有1个元素来理解递归

temp.push_back(S[level]);

recursion(temp, S, level+1, result); // 选择元素s[level]

}

vector<vector<int> > subsets(vector<int> &S) {

sort(S.begin(), S.end());

vector<int> temp;

vector<vector<int> > result;

recursion(temp, S, 0, result);

return result;

}

};

(2) 迭代

通过上图我们可以看出,每次都是在原有的子集后面添加新元素S[i] 并加入到result中就会得到另外一个子集,因此可以采用迭代处理。

[cpp] view
plaincopyprint?





class Solution {

public:

void iterSet(int i, vector<vector<int> > &result, vector<int> &S){

int n = result.size();

for(int j = 0; j < n; j++){

vector<int> temp = result[j]; //集合中原有的子集保持不变,

temp.push_back(i); //但是对于每个子集都新遍历的一个元素S[i]加入构成新子集

result.push_back(temp);

}

}

vector<vector<int> > subsets(vector<int> &S) {

vector<vector<int> > result;

sort(S.begin(), S.end());

vector<int> temp;

result.push_back(temp); // 集合中已有空集

for(int i = 0; i < S.size(); i++){ // 对于每个元素都遍历一遍,

iterSet(S[i], result, S);

}

return result;

}

};

(3)位操作

对于n个元素,每个元素要么加入要么不加入,则会得到一个n位的二进制串,n为二进制串可以看做是一个状态或者说一个子集,每个元素与一位一一对应,状态的大小为1<<n. 对于每个状态j,我们通过判断第k位是否为1,为1则将S[k]加入vec,判断结束,将vec加入result即可。

[cpp] view
plaincopyprint?





class Solution {

public:

vector<vector<int> > subsets(vector<int> &S) {

vector<vector<int> > result;

int n = S.size();

int max = 1 << n; // 最多状态数 存在用1 不存在用0

int i = 0;

sort(S.begin(), S.end());

while(i < max){ // 对每一种状态进行遍历 并将其所对应的元素加入到集合中

int j = i;

vector<int> temp;

/*for(int k= 0; k < n; k++){

if((j & (1<<k)) != 0) temp.push_back(S[k]);

}*/

int index = 0;

while(j>0){

if(j&1) temp.push_back(S[index]); // 第index为1 则加入s[index]位

j = j >> 1;

index++;

}

result.push_back(temp);

i++;

}

return result;

}

};

二:subset 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.

For example,

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

链接:https://leetcode.com/problems/subsets-ii/

分析:与unique paths的区别在于允许元素重复,这是当元素重复时,我们会发现每次加入的子集都是上次迭代的子集,因此需要对迭代法略做改进。

[cpp] view
plaincopyprint?





class Solution {

public:

void iterSet(int i, vector<vector<int> > &result, vector<int> &S, int &t){

int n = result.size();

int count = 0;

int j = 0;

if(i-1>=0 && S[i]==S[i-1])j = n-t; // 如果相等 则只能在上次加入的子集中加入s[i]

for(;j < n; j++){

vector<int> temp = result[j]; //集合中原有的子集保持不变,

temp.push_back(S[i]); //但是对于每个子集都新遍历的一个元素S[i]加入构成新子集

result.push_back(temp);

count++; //主要用来记录每次迭代加入集合个数

}

t = count;

}

vector<vector<int> > subsetsWithDup(vector<int> &S) {

vector<vector<int> > result;

sort(S.begin(), S.end());

vector<int> temp;

result.push_back(temp); // 集合中已有空集

int t = 0;

for(int i = 0; i < S.size(); i++){ // 对于每个元素都遍历一遍,

//if(i-1 < 0 || S[i] != S[i-1]) t = 0;

iterSet(i, result, S, t);

}

return result;

}

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: