之前答案的一个变体,有一个重要的区别:我们发现只有 sorted 的组合总和为目标,然后 然后 生成排列。 [2,3,4] 和 7 的示例:
- 第一步:找到
[2,2,3]和[3,4]
- 第 2 步:生成排列:
[[2, 2, 3], [2, 3, 2], [3, 2, 2], [3, 4], [4, 3]]。
这确实更快。这是代码(permute_unique 取自 here 并使用列表理解进行了优化):
def combinations2(d, sum_to):
def combinations_aux(d, current, sum_to):
for j in range(len(d)):
nex = current+[d[j]]
if sum(nex) == sum_to:
yield nex
elif sum(nex) < sum_to:
yield from combinations_aux(d[j:], nex, sum_to) # d[j:] for elements >= d[j]
def permute_unique(iterable):
# see https://stackoverflow.com/a/39014159/6914441
perms = [[]]
for i in iterable:
perms = [perm[:j] + [i] + perm[j:]
for perm in perms
for j in itertools.takewhile(lambda j:j<1 or perm[j-1] != i, range(len(perm) + 1))
]
return perms
return (p for c in combinations_aux(sorted(set(d)), [], sum_to) for p in permute_unique(c))
基准测试(来自 Ajax1234 的combinations):
def one(): return list(combinations([2,3,4,5,6,7], 35))
def two(): return list(combinations2([2,3,4,5,6,7], 35))
assert sorted([tuple(t) for t in one()]) == sorted([tuple(t) for t in two()])
print (timeit.timeit(one, number=10))
# 154.99560340600146
print (timeit.timeit(two, number=10))
# 23.217042586999014