[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;
}

 

posted on   小橋流水  阅读(307)  评论(0编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述

导航

统计

点击右上角即可分享
微信分享提示