8.4幂集

     《程序员面试金典》(第六版)习题:仅为记录一下以加强印象,不为商业用途,如有侵权请联系删除。以下源码和解释参考了书中源码以及解释。
     一个有n个元素的集合一共有 C n 0 + C n 1 + C n 2 + . . . C n n = 2 n C_n^0+C_n^1+C_n^2+...C_n^n=2^n Cn0+Cn1+Cn2+...Cnn=2n个子集。也可以这样考虑,将集合的每一个子集与一个有n个二进制位的二进制数对应起来,n个二进制位对应于集合中的n个元素,当集合中的该元素在该子集中时,该二进制位为1,不在时为0。因此一个有n个元素的集合一共有 2 n 2^n 2n个子集。当我们知道由集合中前 n − 1 n-1 n1个元素 { a 0 , a 1 , a 2 , . . . , a n − 2 } \left\{a_0, \quad a_1, \quad a_2,...,\quad a_{n-2}\right\} {a0,a1,a2,...,an2}构成的 2 n − 1 2^{n-1} 2n1个子集时,当再加入元素 a n − 1 a_{n-1} an1时怎么得到由n个元素的所有子集?这时由n个元素构成的所有子集为由集合中前 n − 1 n-1 n1个元素构成的 2 n − 1 2^{n-1} 2n1个子集加上将由集合中前 n − 1 n-1 n1个元素构成的 2 n − 1 2^{n-1} 2n1个子集中的每一个子集添加元素 a n − 1 a_{n-1} an1后生成的 2 n − 1 2^{n-1} 2n1个子集即可得到所有由集合中 n n n个元素构成的 2 n 2^n 2n个子集。这很容易从前面的将子集与一个二进制数对应起来的思想得到。相当于一个n位二进制数的前 n − 1 n-1 n1位都已经确定,第 n − 1 n-1 n1位为0或1时就可以生成两个新的n为二进制数。第 n − 1 n-1 n1位为0时相当于由不包含元素 a n − 1 a_{n-1} an1构成的子集,第 n − 1 n-1 n1位为1时相当于由包含元素 a n − 1 a_{n-1} an1构成的子集。

//开始调用时取index的值为0
vector<vector<int>> getSubSets(vector<int> set,int index)
{
	vector<vector<int>> allSubSets;
	if (set.size() == index)
	{
		allSubSets.push_back(vector<int>());
	}
	else
	{
		allSubSets = getSubSets(set, index + 1);
		int item = set.at[index];
		vector<vector<int>> moreSubSets;
		for (vector<int> currentSubSet : allSubSets)
		{
			vector<int> newSubSet;
			newSubSet = currentSubSet;
			newSubSet.push_back(item);
			moreSubSets.push_back(newSubSet);
		}
		allSubSets.insert(allSubSets.end(), moreSubSets.begin(), moreSubSets.end());
	}
	return allSubSets;
}

     以下算法更直接的利用了将集合的每一个子集与一个有n个二进制位的二进制数对应起来的思想。对于0到 2 n − 1 2^{n}-1 2n1一共 2 n 2^n 2n个二进制数,逐一求得其对应的子集,然后将它们合起来即为所求。

vector<int> convertIntToSet(int x, vector<int> set)
{
	vector<int> subset;
	int index = 0;
	for (int k=x;k>0;k>>=1)
	{
		if ((k & 1) == 1)
			subset.push_back(set.at(index));
		index++;
	}
	return subset;
}

vector<vector<int>> getSubSets(vector<int> set)
{
	vector<vector<int>> allSubSets;
	int max = 1 << set.size();
	for (int k = 0; k < max; k++)
	{
		vector<int> subset = convertIntToSet(k, set);
		allSubSets.push_back(subset);
	}
	return allSubSets;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqssss121dfd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值