[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 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。