《cracking the coding interview》第8.3节
例如,对于集合S={a,b} ,子集有 { },{a},{b},{a,b} 四种。
对于集合S,
分类方法1,分为元素个数为0,1,2...s (s 为集合的所有元素个数)种,计算比较复杂;
分类方法2,每个元素出现或者不出现,有2^n 个字集合。
思路是:首先子集为{},然后添加一个元素a,集合为{},{a}; 然后添加一个元素b,集合为{b},{b,a}; 前面的加起来就是所求集合。
代码为:
vecs 表示向量的向量,及保存之前的集合,more表示构成的新集合
void f(int *A,int n){
vector<vector<int> > vecs;
vector<int> more;
vecs.push_back(more);
for(int i=0;i<n;i++){
int size=vecs.size();
for(int j=0;j<size;j++){
vector<int> iter=vecs[j];
vector<int> temp;
for(int k=0;k<iter.size();k++){
temp.push_back(iter[k]);
}
temp.push_back(A[i]);
vecs.push_back(temp);
}
}
int count=0;
for(i=0;i<vecs.size();i++){
vector<int> iter=vecs[i];
for(int k=0;k<iter.size();k++){
cout<<iter[k]<< " ";
}
cout<<endl;
count++;
}
cout<<"count="<<count<<endl;
}
方法3:
然而我们发现的一个事实是,所有元素或者出现或者不出现,就如计算中的数字,或者0或者1,这是一个 启发。也就是说2^n种子集,其实可以表示为一:2^n 长度的二进制序列,其中每个位出现一次1。
比如 三个数{a,b,c} 可以用一个三位二进制表示 000,001,010,011,100,101,110,111,其中每个组合中的1代表对应元素的组合。
void f2(int *A,int n){
int *p=new int[n];
int p_i=0;
int max=1<<n;
int count=0;
for(int i=0;i<max;i++){
int k=i;
int index=0;
p_i=0;
while(k>0){
if((k&1)>0){
p[p_i++]=A[index];
}
k>>=1;
index++;
}
for(int j=0;j<p_i;j++){
cout<<p[j]<<" ";
}
count++;
cout<<endl;
}
cout<<"count="<<count<<endl;
}