如何使用Python计算组合以达到总计(总和)?

时间:2019-01-08 06:45:46

标签: python itertools

给出一个整数总数,计算表示总数的可能方式的数量。 总和为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

2 个答案:

答案 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=5nums=[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