python递归组合

时间:2014-05-25 04:14:49

标签: python recursion combinations

如何编写计算函数:

C(n,k)= 1                          if k=0
        0                          if n<k
        C(n-1,k-1)+C(n-1,k)     otherwise

到目前为止,我有:

def choose(n,k):
if k==0:
   return 1
elif n<k:
   return 0
else:

5 个答案:

答案 0 :(得分:2)

假设你的问题中缺少的操作数是减法运算符(感谢lejlot),这应该是答案:

def choose(n,k):
  if k==0:
     return 1
  elif n<k:
     return 0
  else:
     return choose(n-1, k-1) + choose(n-1, k)

请注意,在大多数Python系统中,max depth or recursion limit仅为1000.之后它将引发异常。您可能需要通过将此递归函数转换为迭代函数来解决此问题。

这是一个示例迭代函数,它使用堆栈来模拟递归,同时避免Python的最大递归限制:

def choose_iterative(n, k):
  stack = []
  stack.append((n, k))
  combinations = 0

  while len(stack):
    n, k = stack.pop()
    if k == 0:
      combinations += 1
    elif n<k:
      combinations += 0 #or just replace this line with `pass`
    else:
      stack.append((n-1, k))
      stack.append((n-1, k-1))

  return combinations    

答案 1 :(得分:0)

来自维基百科的解决方案(http://en.wikipedia.org/wiki/Binomial_coefficient

def choose(n, k):
    if k < 0 or k > n:
        return 0
    if k > n - k: # take advantage of symmetry
        k = n - k
    if k == 0 or n <= 1:
        return 1
    return choose(n-1, k) + choose(n-1, k-1)

答案 2 :(得分:0)

您正在尝试计算从n个元素中选择k的选项数量:

def choose(n,k):
    if k == 0: 
       return 1 # there's only one option to choose zero items out of n
    elif n < k:
       return 0 # there's no way to choose k of n when k > n
    else:
        # The recursion: you can do either
        # 1. choose the n-th element and then the rest k-1 out of n-1
        # 2. or choose all the k elements out of n-1 (not choose the n-th element)
        return choose(n-1, k-1) + choose(n-1, k)

答案 3 :(得分:0)

就像这样

def choose(n,k):
    if k==0:
        return 1
    elif n<k:
        return 0
    else:
        return choose(n-1,k-1)+choose(n-1,k)

修改

这是一种简单的方法,有效的方法可以看一下维基百科和spencerlyon2 answer

答案 4 :(得分:0)

从指数变为线性时间

到目前为止,所有答案均以指数时间 O(2n)运行。但是,通过更改一行代码,可以在O(k)中运行。


说明:

指数运行时间的原因是每次递归都会使用这行代码(see Ideone here)将问题分成重叠的子问题:

def choose(n, k):
    ...
    return choose(n-1, k-1) + choose(n-1, k)

要了解为什么这么糟糕,请考虑choose(500, 2)的例子。 500 choose 2的数值为500*499/2;但是,使用上面的递归需要250499递归调用来计算它。显然这是过度的,因为只需要3次操作。

要将此改进为线性时间,您需要做的就是选择一个不会分裂为两个子问题的不同递归(wikipedia上有很多)。

例如,以下递归是等效的,但仅使用3递归调用来计算choose(500,2)see Ideone here):

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

改进的原因是每次递归只有一个子问题,每次调用时k减少1。这意味着我们可以保证此递归仅需k + 1次递归或O(k)。这是改变单行代码的巨大改进!

如果您想更进一步,可以利用“n选择k”中的对称性来确保k <= n/2see Ideone here):

def choose(n,k):
    ...
    k = k if k <= n/2 else n - k            # if k > n/2 it's equivalent to k - n
    return ((n + 1 - k)/k)*choose(n, k-1)