[CareerCup 8.3] 求一个集合的所有子集
这是一个很经典的问题,相对来说,也是比较简单的问题。首先,通过数学知识我们知道一个含n个元素的集合一共有2^n个子集。
方法1:采用递归的方法
举个例子来说{a, b, c}
我们可以先求{b, c}的所有子集{}, {b}, {c}, {b, c}
然后将{b, c}的所有子集与a进行组合与{b, c}的所有子集一起,形成{a, b, c}的所有子集
{}, {b}, {c}, {b, c}, {a}, {a, b}, {a, c}, {a, b, c}
代码如下:
/**
求一个集合的所有子集
我们可以递归来考虑这个问题
举个例子来说{a, b, c}
我们可以先求{b, c}的所有子集{}, {b}, {c}, {b, c}
然后将{b, c}的所有子集与a进行组合与{b, c}的所有子集一起,形成{a, b, c}的所有子集
{}, {b}, {c}, {b, c}, {a}, {a, b}, {a, c}, {a, b, c}
**/
vector<set<int>> subset(set<int> s)
{
if (s.empty())
return vector<set<int>>();
int b = *s.begin();
s.erase(s.begin());
vector<set<int>> v = subset(s);
vector<set<int>> result;
set<int> t;
result.push_back(t);
t.insert(b);
result.push_back(t);
for (vector<set<int>>::iterator it = v.begin(); it != v.end(); it++)
{
if (! it->empty())
{
set<int> n(*it);
n.insert(b);
result.push_back(*it);
result.push_back(n);
}
}
return result;
}
方法2:从二进制的观念来考虑
注意一个n个元素的集合有2^n个子集
比如一个集合{a,b,c}有8个子集
注意到求子集的时候,有个特点,我们就只要确定一个元素是否在子集中
比如所有的元素都不在子集中,那么这个子集为空集
如果所有的元素都在子集中,那么这个子集为这个集合本身
对于一个n个元素,可以用n位2进制来表示
比如{a, b, c}可以用3位2进制表示
0 000 {}
1 001 {a}
2 010 {b}
3 011 {a, b}
4 100 {c}
5 101 {a, c}
6 110 {b, c}
7 111 {a, b, c}
这种算法有一个问题,就是当集合的大小超过32后,就会溢出,但是考虑一下2^32个结果也基本上存不下了。
代码如下:
/**
注意一个n个元素的集合有2^n个子集
比如一个集合{a,b,c}有8个子集
注意到求子集的时候,有个特点,我们就只要确定一个元素是否在子集中
比如所有的元素都不在子集中,那么这个子集为空集
如果所有的元素都在子集中,那么这个子集为这个集合本身
对于一个n个元素,可以用n位2进制来表示
比如{a, b, c}可以用3位2进制表示
0 000 {}
1 001 {a}
2 010 {b}
3 011 {a, b}
4 100 {c}
5 101 {a, c}
6 110 {b, c}
7 111 {a, b, c}
**/
vector<set<int>> subset_two(set<int> s)
{
int count = s.size();
int i, j;
vector<set<int>> v;
for (i = 0; i < 1 << count; i++)
{
set<int> t;
j = 0;
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
if (get_bit(i, j++))
t.insert(*it);
}
v.push_back(t);
}
return v;
}
测试代码:
int main()
{
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
vector<set<int>> v = subset_two(s);
for (vector<set<int>>::iterator it = v.begin(); it != v.end(); it++)
{
for (set<int>::iterator sit = it->begin(); sit != it->end(); sit++)
cout << *sit << ' ';
cout << endl;
}
return 0;
}
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。
浙公网安备 33010602011771号