我在尝试编写一个函数组合时遇到了很大的困难,该函数组合以两个自然数 k 和 n 作为输入,并返回大小为 k 且总和为 n 的所有元组的集合。我关心的是找到同一组数字的不同排列。
我从 python 中找到了这个文档,可以在不使用 itertools 的情况下进行计算。
我的问题允许使用这些库
import sys
import numpy as np
import scipy as sp
from scipy.special import *
def compositions(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)
Given input compositions(3, 4)
output:
all possible combinations
1 + 2 + 1
2 + 1 + 1
1 + 1 + 2
actual output from composition(3,4):
{(1, 1, 2,), (1, 2, 1), (2, 1, 1)}
Run Code Online (Sandbox Code Playgroud)
任何帮助,将不胜感激。
首先,请注意,随着 ,解的长度增长得非常快n,因此,如果您使用大量数字,计算此问题的时间和内存可能会让您感到震惊。
话虽如此,请注意,获取所有数字组合并检查总和是一个坏主意,因为您会生成很多情况,仅通过检查第一个数字就知道它们不起作用。换句话说,您需要尽快修剪数组的搜索。
思考这类问题以及更好更快的实现是非常有趣的。在这里你有一种可能性:
def gen_combinations(k, n):
assert n > k > 1
to_process = [[i] for i in range(1, n+1)]
while to_process:
l = to_process.pop()
s = sum(l)
le = len(l)
#If you do not distiguish permutations put xrange(l[-1],n-s+1)
# instead, to avoid generating repeated cases.
# And if you do not want number repetitions, putting
# xrange(l[-1] + 1, n-s+1) will do the trick.
for i in xrange(1, n-s+1):
news = s + i
if news <= n:
newl = list(l)
newl.append(i)
if le == k-1 and news == n:
yield tuple(newl)
elif le < k-1 and news < n:
to_process.append(newl)
Run Code Online (Sandbox Code Playgroud)
这是一个生成器,如果您需要列表,只需执行,例如list(gen_combinations(3,4))。