How would I efficiently find all the possible combinations of n positive integers adding up to a given number k in Python?
I know I could solve this by filtering all the possible combinations:
import itertools
def to_sum_k(n, k):
for i in itertools.product(range(1, k - n + 2), repeat=n):
if sum(i) == k:
yield i
print(list(to_sum_k(3, 5)))
# [(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]
I have seen something similar has been discussed in abstract way here, but I do not see a simple way of translating this into code.
Also, I would prefer an iterative solution over a recursive one.
解决方案
A recursive solution based on this:
def to_sum_k_rec(n, k):
if n == 1:
yield (k,)
else:
for x in range(1, k):
for i in to_sum_k_rec(n - 1, k - x):
yield (x,) + i
print(list(to_sum_k_rec(3, 5)))
# [(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]
And an iterative one:
import itertools
def to_sum_k_iter(n, k):
index = [0] * (n + 1)
index[-1] = k
for j in itertools.combinations(range(1, k), n - 1):
index[1:-1] = j
yield tuple(index[i + 1] - index[i] for i in range(n))
print(list(to_sum_k_iter(3, 5)))
# [(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]
Time-wise, the recursive solution seems to be fastest:
%timeit list(to_sum_k_OP(4, 100))
# 1 loop, best of 3: 13.9 s per loop
%timeit list(to_sum_k_rec(4, 100))
# 10 loops, best of 3: 101 ms per loop
%timeit list(to_sum_k_iter(4, 100))
# 1 loop, best of 3: 201 ms per loop