您的位置:首页 > 职场人生

程序员面试金典: 9.9 递归和动态规划 9.4求某集合的所有子集

2017-01-08 18:17 369 查看
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>

using namespace std;

/*
问题:编写一个方法,返回某集合的所有子集。
分析:什么集合,比如具体举个例子。一个有n个不同元素的集合,其子集为2^(n)
那么依次生成时间复杂度为O(2^n),这个时间复杂度要比O(n!)要大。
暴力破解应该是直接生成。
如果用递归:先生成一个初始元素,假设为abc,那么最后一个元素可以和倒数第二个元素进行交换
没明白题目的意思。

题目的实际意思是给定P={a1,a2,...an}
求出其所有子集。问题的关键是如何根据已经生成的元素来生成后续的集合。
比如当前子集元素为a,后续如何生成下一个子集中元素
注意该题并不是求字符串的全排列,全排列对于不同的顺序认为是不同的字符串,而集合中除了位置不同其余都相同的集合会认为是同一个。
P(0)={}
P(1)={ {}, {a1} }
P(2)={ {}, {a1}, {a2}, {a1,a2} }
P(3)={ {}, {a1}, {a2}, {a1,a2} ,{a3} , {a1,a3}, {a2,a3}, {a1,a2,a3}  }
P(2) + a3={ {a3} , {a1,a3}, {a2,a3}, {a1,a2,a3} }
观察P(3)-P(2)={                  {a3} , {a1,a3}, {a2,a3}, {a1,a2,a3} }
发现从P(2)构造P(3)只需要复制P(2),然加上a3,
即P(n) = P(n-1) + [ P(n-1) + an ]

输入:
3(集合中元素个数)
a b c(集合中各个元素)
输出:
{} {a} {b} {c} {a,b} {a,c} {b,c} {a,b,c}

书上解法2:
因为n个元素,子集个数为2^n,那么对于,对于每个元素,存在选择和不选择,可以用1和0表示,等于实际上就是
0~2^n - 1 的范围内,根据提取的二进制1的个数去获取集合中对应位置的元素来构成

关键:
1 	 题目的实际意思是给定P={a1,a2,...an}
求出其所有子集。问题的关键是如何根据已经生成的元素来生成后续的集合。
比如当前子集元素为a,后续如何生成下一个子集中元素
注意该题并不是求字符串的全排列,全排列对于不同的顺序认为是不同的字符串,而集合中除了位置不同其余都相同的集合会认为是同一个。
P(0)={}
P(1)={ {}, {a1} }
P(2)={ {}, {a1}, {a2}, {a1,a2} }
P(3)={ {}, {a1}, {a2}, {a1,a2} ,{a3} , {a1,a3}, {a2,a3}, {a1,a2,a3}  }
P(2) + a3={ {a3} , {a1,a3}, {a2,a3}, {a1,a2,a3} }
观察P(3)-P(2)={                  {a3} , {a1,a3}, {a2,a3}, {a1,a2,a3} }
发现从P(2)构造P(3)只需要复制P(2),然加上a3,
即P(n) = P(n-1) + [ P(n-1) + an ]

2
因为n个元素,子集个数为2^n,那么对于,对于每个元素,存在选择和不选择,可以用1和0表示,等于实际上就是
0~2^n - 1 的范围内,根据提取的二进制1的个数去获取集合中对应位置的元素来构成
vector<string> getSubset(vector<string>& vecInputData , int n)
{
vector<string> vecResult;
int index = 0;
for( int k = n ; k > 0 ; k >>= 1)
{
//如果某个元素是被选中的
if( (k & 1) == 1)
{
string value = vecInputData.at(index);
vecResult.push_back(value);
}
index++;
}
return vecResult;
}

3
//将整个元素都拷贝到结果集中,用插入来做
vecResult.insert(vecResult.end() , vecTemp.begin() , vecTemp.end() );
*/

string join(vector<string>& vecStr)
{
if(vecStr.empty())
{
return "";
}
stringstream ss;
ss << "{";
int size = vecStr.size();
for(int i = 0 ; i < size ; i++)
{
if( i != 0)
{
ss << "," << vecStr[i];
}
else
{
ss << vecStr[i] ;
}
}
ss << "}";
string sResult = ss.str();
return sResult;
}

vector<string> getSubset(vector<string>& vecInputData , int n)
{
vector<string> vecResult;
int index = 0;
for( int k = n ; k > 0 ; k >>= 1)
{
//如果某个元素是被选中的
if( (k & 1) == 1)
{
string value = vecInputData.at(index);
vecResult.push_back(value);
}
index++;
}
return vecResult;
}

void generateSubset_ByCombineNumber(vector<string>& vecInputData ,vector<string>& vecResult )
{
if(vecInputData.empty())
{
return ;
}
int size = vecInputData.size();
int max = 1 << size;
vector<string> subset;
string sResult;
for(int k = 0 ; k < max; k++)
{
subset = getSubset(vecInputData , k);
sResult = join(subset);
vecResult.push_back(sResult);
}
}

//n用于表示当前计算的子集的元素个数
void generateSubset(vector<string>& vecInputData , vector<string>& vecResult , int n)
{
if(vecInputData.empty())
{
return ;
}
//只有空集,返回
if(-1 == n)
{
vecResult.push_back("");
}
else
{
//先递归P(n-1),后处理
generateSubset(vecInputData , vecResult , n - 1);
// P(n) = P(n-1) + [ P(n-1) + an ]
vector<string> vecTemp(vecResult);
//对拷贝出来的每一个元素都加上 当前元素
string val = vecInputData.at(n);
for(vector<string>::iterator it = vecTemp.begin() ; it != vecTemp.end() ; it++)
{
if(!(*it).empty())
{
*it += "," + val;
}
else
{
*it = val;
}
}
//将整个元素都拷贝到结果集中,用插入来做
vecResult.insert(vecResult.end() , vecTemp.begin() , vecTemp.end() );
}
}

void process()
{
int n;
vector<string> vecStr;
vector<string> vecResult;
string str;
while(cin >> n)
{
vecStr.clear();
vecResult.clear();
//考虑到n为0时,对应空集,这样处理
//vecStr.push_back("");
for(int i = 1 ; i <= n ; i++)
{
cin >> str;
vecStr.push_back(str);
}
//generateSubset_ByCombineNumber(vecStr , vecResult);
generateSubset(vecStr , vecResult , vecStr.size() - 1 );
//添加括号
for(vector<string>::iterator it = vecResult.begin() ; it != vecResult.end() ; it++)
{
*it = "{" + (*it) + "}";
cout << (*it) << " ";
}
cout << endl;
}
}

int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐