您的位置:首页 > 其它

78. Subsets&集合的子集&Power Set

2014-03-05 11:49 405 查看
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>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ret;
vector<int> cur;
subsetsCore(nums,cur,ret,0);

return ret;

}

void subsetsCore(vector<int>&nums,vector<int>& cur,vector<vector<int>>& ret,int begin)
{
ret.push_back(cur);
for(int i = begin;i<nums.size();++i)
{
if(i==begin || nums[i] != nums[i-1])
{
cur.push_back(nums[i]);
subsetsCore(nums,cur,ret,i+1);
cur.pop_back();
}
}

}
};


这个问题编程实现就是不会,看了别人的答案,想了半天,微微懂点儿。

class Solution {
public:
vector<vector<int>> subsets(vector<int> &S) {
vector<vector<int>> ret;
vector<int> cur;
sort(S.begin(),S.end());
subsets(S,0,cur,ret);
return ret;

}

void subsets(vector<int> &S,int step,vector<int> &cur,vector<vector<int>> &ret)
{
if(step == S.size())
{
ret.push_back(cur);
return;
}

//不选择S[step]
subsets(S,step+1,cur,ret);

//选择S[Step]
cur.push_back(S[step]);
subsets(S,step+1,cur,ret);
cur.pop_back();

}
};



题目描述

请编写一个方法,返回某集合的所有非空子集。

给定一个int数组A和数组的大小int n,请返回A的所有非空子集。保证A的元素个数小于等于20,且元素互异。各子集内部从大到小排序,子集之间字典逆序排序,见样例。
测试样例:
[123,456,789]

返回:{[789,456,123],[789,456],[789,123],[789],[456 123],[456],[123]}


首先,对时间复杂度和空间复杂度进行评估。

一个集合会有多少个子集?生成一个子集时,每个元素都可以“选择”在或不在这个子集中。也就是说,第一个元素有两种选择:它要么在集合中,要么不在集合中。同样,第二个元素也有两个选择,依此类推,共有

个子集。因此,在时间或空间复杂度上,不可能比

更好。

集合

的所有子集组成的集合称为幂集,用符号表示为:

或者



解法1:递归

这道题非常适合简单构造法。假设我们正尝试找出集合

的所有子集,可以从终止条件开始。

终止条件n=0

空集合只有一个子集


情况:n=1

集合

有两个子集,




情况:n=2

集合

有四个子集:








情况:n=3

我们需要找出一种方法,根据之前的答案产生n=3时的答案。

比较n=3和n=2时的结果,可以看到


=









=
















二者的不同之处在于,所有含有

的子集,

都没有。

所以,是需要复制

里的子集,并在这些子集中添加

,然后将二者合并在一起,就可以得到



情况:n>0

要求

,先求

,结果复制一份,并在每个复制后的集合中加入



class Subset {
public:
vector<vector<int> > getSubsets(vector<int> A, int n)
{
vector<vector<int> > ret = getSubsets(A,n,n);

for(vector<vector<int>>::iterator iter=ret.begin(); iter!=ret.end(); )
{
if( (*iter).empty())
iter = ret.erase(iter);
else
iter ++ ;
}
return ret;
}

vector<vector<int> > getSubsets(vector<int> A, int n,int index) {
vector<vector<int>> allSubsets;
if (index == 0)
{
vector<int> nullSubSet;
allSubsets.push_back(nullSubSet);
return allSubsets;
}
else
{
vector<vector<int>> moreSubsets = getSubsets(A,n,index-1);
vector<vector<int>> copyOfMoreSubsets(moreSubsets);
int value = A[index-1];
for(vector<vector<int>>::iterator it = moreSubsets.begin();it!= moreSubsets.end();++it)
{
(*it).push_back(value);

allSubsets.push_back(*it);
}

for(vector<vector<int>>::iterator it = copyOfMoreSubsets.begin();it!= copyOfMoreSubsets.end();++it)
{

allSubsets.push_back(*it);
}

for(vector<vector<int>>::iterator it = allSubsets.begin();it!= allSubsets.end();++it)
{
sort((*it).begin(),(*it).end(),greater<int>());
}
return allSubsets;

}
}

};


这个方法的时间和空间复杂度都是。

解法2:组合数学

注意当我们在产生一个集合时,对每一个元素我们有两种选择:(1)元素在集合中(“YES”状态)或者(2)元素不在集合中(“NO”状态)。这意味着,每一个子集是一个yes/no的集合,例如“YES,YES,NO,NO,YES,NO”。

这样我们可以得到个可能的集合。对所有元素,我们怎样可以迭代访问所有可能的“YES/NO”状态序列?每个“YES”可以被当作1,每个“NO”可以被当作0,那么每个子集合就可以被表示为一个二进制串。

要产生所有子集合就转换成产生所有的二进制数字(也就是,所有的整数。)

我们迭代访问从0到(不包括)的所有数字,并将二进制表示转换成一个集合。

class Solution {
public:
std::vector<std::vector<int> > subsets(std::vector<int> &A) {
vector<vector<int> > ret;
int max = 1<<A.size();/*compute 2^n*/

for (int i = 0;i<max;++i)
{
vector<int> subset = convertIntToSet(A,i);
ret.push_back(subset);
}
return ret;
}
private:
vector<int> convertIntToSet(const vector<int>& A,int num)
{
vector<int> ret;
int index = 0;
for(int i = num;i>0;i>>=1)
{
if((i&1) == 1)
ret.push_back(A[index]);
++index;
}

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