给定一个整数列表,是否有一种算法可以计算幂集中的集合数?这不应包括空集,例如,{1,2,3}
与 相同{2,3,1}
,因此不应将它们计算两次(即幂集)。
注意:列表的元素不一定是唯一的。
集合被定义为仅包含唯一/不同的元素。一个集合的幂集中的集合数是2^elements_in_set
。powerset 包含空集,所以你想要的是2^elements_in_set - 1
.
所以,一个列表的集合的幂集中的集合数是2^unique_elements_in_list
,没有空集的数是2^unique_elements_in_list - 1
。
另一种思考方式是创建一个位数组,其大小与唯一元素的数量相同。数组中的每一位对应于该元素是否在该特定的幂集元素中。假设您的元素是 9、7、4。这是映射的样子:
powerset element | 9 | 7 | 4
-----------------+---+---+---
[] | 0 | 0 | 0
[4] | 0 | 0 | 1
[7] | 0 | 1 | 0
[4, 7] | 0 | 1 | 1
[9] | 1 | 0 | 0
[4, 9] | 1 | 0 | 1
[7, 9] | 1 | 1 | 0
[4, 7, 9] | 1 | 1 | 1
所以你真的只是最终以二进制计算。你可以用n
二进制数组成多少个数字?2^n
. 除了零还有多少?2^n - 1
.
要实际生成 powerset,这里有一些代码。请注意,为方便起见,它使用列表。
def gen_powerset(l):
if not l:
yield []
return
for sub_powerset in gen_powerset(l[1:]):
yield sub_powerset
yield [l[0]] + sub_powerset
例子:
>>> list(gen_powerset(list(set([1, 4, 2, 2, 3]))))
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3],
[4], [1, 4], [2, 4], [1, 2, 4], [3, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]
>>> len(list(gen_powerset(list(set([1, 4, 2, 2, 3])))))
16
注意 16 是2^4
中唯一元素的数量[1, 4, 2, 2, 3]
。
不过,将 2 提高到一个幂比生成整个集合来计算它要容易得多!
您可以使用 itertools组合函数来生成 S 的每个子集而无需重复。
def powerset(iterable):
result = set()
for l in xrange(1, len(iterable) + 1):
for subset in itertools.combinations(iterable, l):
result.add(subset)
return sorted(result, key=len)
S = ['x', 'y' ,'z', 'y']
for subset in powerset(S):
print subset
结果:
('z',)
('y',)
('x',)
('z', 'y')
('x', 'y')
('y', 'y')
('x', 'z')
('y', 'z')
('y', 'z', 'y')
('x', 'y', 'z')
('x', 'z', 'y')
('x', 'y', 'y')
('x', 'y', 'z', 'y')
from itertools import chain, combinations
i = set([1, 2, 3])
for z in chain.from_iterable(combinations(i, r) for r in range(len(i)+1)):
print z
重复项对 powerset 中的集合数量没有影响 - 您可以简单地使用 powerset 公式 - (如下所示),其中是唯一元素的数量。2n-1
n
动机 - 每个独特的元素可以被选择,也可以不被选择(我们选择哪个事件并不重要),所以每个独特元素有 2 种可能性,因此总共有可能性。是为了排除空集。2*2*...*2 = 2n
-1
带有重复项的“集”:
如果我们假设每个“集合”可以包含重复项(但出现次数不超过输入中的次数),则更有趣的问题是生成幂集。
因此,对于类似的东西1,2,2,3
,一些需要计算的“集合”将是2,2,3
, 1,2,2
,2,2
等。
让我们考虑一下。
对于1,2,2,3
,我们可以选择 1 或不选择它(2 种可能性),我们可以选择 0-2 个二的(3 种可能性),我们可以选择 3 或不选择它(2 种可能性)。
请注意,每个不同的元素都有number of occurrences + 1
可能。
所以,伪代码:
setCount = 1
for each distinct element e
setCount *= 1 + number of occurrences of e
output setCount-1