幂集
集合 S
的幂集是 S
所有子集的集合,包括空集和 S
本身。集合 S
的幂集表示为 P(S)
。
例如对于 {x, y, z}
,子集如下:
{
{}, //(也表示为空集 ∅ 或空集)
{x},
{y},
{z},
{x, y},
{x, z},
{y, z},
{x, y, z}
}
这里是如何说明集合 {x, y, z}
的幂集中的元素,并按照包含关系排序的:
子集数量
如果 S
是一个有 |S| = n
个元素的有限集合,那么 S
的子集数量是 |P(S)| = 2^n
。这个事实是符号 2^S
的动机,可以简单地这样证明:
首先,以任何方式对
S
的元素进行排序。我们用{γ1, γ2, ..., γn}
的格式写下S
的任何子集,其中γi , 1 ≤ i ≤ n
可以取0
或1
的值。如果γi = 1
,则S
中的第i
个元素在子集中;否则,第i
个元素不在子集中。显然,通过这种方式可以构建的不同子集数量是2^n
,因为γi ∈ {0, 1}
。
算法
位解决方案
二进制表示中范围从 0
到 2^n
的每个数字都完全满足我们的需求:它通过其位(0
或 1
)显示是否需要包含集合中的相关元素。例如,对于集合 {1, 2, 3}
,0b010
的二进制数意味着我们只需要将 2
添加到当前集合中。
abc |
子集 | |
---|---|---|
0 |
000 |
{} |
1 |
001 |
{c} |
2 |
010 |
{b} |
3 |
011 |
{c, b} |
4 |
100 |
{a} |
5 |
101 |
{a, c} |
6 |
110 |
{a, b} |
7 |
111 |
{a, b, c} |
见 bwPowerSet.js 文件了解位解决方案。
回溯解决方案
在回溯方法中,我们不断尝试将集合的下一个元素添加到子集中,记住它,然后删除它并尝试下一个元素。
见 btPowerSet.js 文件了解回溯解决方案。
级联解决方案
这可以说是生成幂集的最简单解决方案。
我们从空集开始:
powerSets = [[]]
现在,假设:
originalSet = [1, 2, 3]
将原始集中的第一个元素添加到所有现有集合中:
[[]] ← 1 = [[], [1]]
将第二个元素添加到所有现有集合中:
[[], [1]] ← 2 = [[], [1], [2], [1, 2]]
将第三个元素添加到所有现有集合中:
[[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
以此类推,直到原始集中的其余元素。在每次迭代中,集合的数量都会翻倍,因此我们将得到 2^n
个集合。
见 caPowerSet.js 文件了解级联解决方案。