递归函数,用于查找组合而不会达到python中的内置限制

时间:2018-09-22 22:04:54

标签: python recursion combinations

我整理了一个函数,可以使用递归查找组合,而不会达到python中的内置限制。例如,您可以计算:选择(1000,500)。 这就是现在的样子:

def choose(n, k):
    if not k: 
    return 1 .
elif n < k: 
    return 0
else:
    return ((n + 1 - k) / k) * choose(n, k - 1)

它完全按照我希望的方式工作。如果k为0,则返回1,如果n小于k,则返回0(这是根据我在维基百科上找到的数学定义)。但是,问题是我不太了解最后一行(当我浏览网络时找到了它)。此刻我正在使用的最后一行之前,这是我在函数中拥有的最后一行:

return choose(n-1,k-1) + choose(n-1, k) 

我也在Wikipedia上找到了(尽管我也不是100%理解)。但是由于python中的内置限制,它总是会导致错误,而我正在使用的新行不会导致这种错误。我知道新行在程序中的工作效率更高,因为例如,我们不将其拆分为两个子问题。

再说一遍..我要问的是,是否有任何一种灵魂可以(以一种可以理解的方式)解释这一行代码在函数中的工作方式:

return ((n + 1 - k) / k) * choose(n, k - 1)

2 个答案:

答案 0 :(得分:0)

您首先需要知道如何定义组合C(n,k)。 C(n,k)的公式为:

或等效地:

可以重新构造为递归表达式:

这是您实现的。

对于第二种实现,这是Pascal's formula。递归实现将非常慢(并且可能会堆栈溢出,是的)。一种更有效的实现方式是将每个C(n,k)存储在二维数组中,以便按顺序计算每个值。

答案 1 :(得分:0)

剧透:最重要的是您应该使用封闭格式n! / (k! (n - k)!)

在许多其他语言中,解决方案是使函数tail-recursive,尽管Python不支持这种优化。因此,实施递归解决方案根本不是最佳选择。

您可以使用sys.setrecursionlimit来增加最大递归深度,但这并不是最佳选择。

一种改进是通过迭代计算 n-choose-k

def choose(n, k):
    if n < k:
        return 0

    ans = 1
    while k > 0:
        ans *= (n + 1 - k) / k
        k -= 1

    return ans

尽管如此,由于浮点运算,以上内容会累积一个错误。因此,最好的方法是使用 n-choose-k 的封闭形式。

from math import factorial

def choose(n, k):
    return factorial(n) / (factorial(k) * factorial(n - k))