给出一个整数总数,计算表示总数的可能方式的数量。 总和为5,而整数可以视为[1,2,3]
定位总和的5种方法是:
1 + 1 + 1 + 1 + 1 = 5
1 + 1 + 1 + 2 = 5
1 + 2 + 2 = 5
1 + 1 + 3 = 5
2 + 3 = 5
输入是5、3,其中3是达到总数5的范围[1,2,3]
输出为5
答案 0 :(得分:1)
我认为使用combinations()
不会在这里起作用-该函数返回您传递的数组的组合,但不会创建任何给定元素的重复项。您可以通过使用变体combinations_with_replacement()
来解决此问题,但是即使那样,您最终仍然会得到大量无效组合,并且对于冗长的列表,运行时将变得很棘手。
相反,请考虑以下类似的递归解决方案。
def reps(target, nums):
res = []
for i, v in enumerate(nums):
if target - v > 0:
res += [[v] + l for l in reps(target-v, nums[i:])]
elif target - v == 0:
res += [[v]]
return res
在这里,我获取目标总和和数字列表,然后尝试从目标中减去每个数字。如果差异恰好等于0,则将最后一个值添加到列表中。如果其大于零,我将尝试通过使用新的目标值和原始数字的子集调用reps()
来将元素添加到列表中,以防止相同答案的排列。我将所有这些结合起来,从列表中选择之前选择的值,然后以这种方式继续操作,直到建立了所有组合的列表。
示例target=5
和nums=[1,2,3]
-
[[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 3], [1, 2, 2], [2, 3]]
答案 1 :(得分:0)
因为您的问题只需要可能性的数量,而不是可能性本身,所以这是最快的解决方法之一:
def partitions(n, m):
if n <= 1:
return 1
if m > n:
return partitions(n, n)
total = 0
for i in range(1, m + 1):
total += partitions(n - i, i)
return total
在这里,n
是您要分区的数字,m
是最大数字的限制。它甚至可以非常快速地处理非常大的数字:
In [1]: def partitions(n, m):
...: if n <= 1:
...: return 1
...: if m > n:
...: return(partitions(n, n))
...:
...: total = 0
...: for i in range(1, m + 1):
...: total += partitions(n - i, i)
...:
...: return total
...:
In [2]: partitions(5, 3)
Out[2]: 5
In [3]: partitions(10, 5)
Out[3]: 30
In [4]: partitions(50, 30)
Out[4]: 202139 # returned in less than a second