[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}
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /** 求一个集合的所有子集 我们可以递归来考虑这个问题 举个例子来说{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个结果也基本上存不下了。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /** 注意一个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; } |
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述