Python 你能解释一下这个“递归”吗;n选择“k”;对我说什么?

Python 你能解释一下这个“递归”吗;n选择“k”;对我说什么?,python,recursion,Python,Recursion,下面是一个带有参数n和k的子集问题的代码。n表示学生总数,k表示我希望从n中获得的学生数量。代码试图给出从n个学生中抽取k个学生的可能组合数 def subset(n, k): if k == 0: return 1 if n == k: return 1 else: return subset(n-1, k-1) + subset(n-1, k) 我理解递归调用的第一部分,但理解+子集(n-1,k)部分有困难。有人能给

下面是一个带有参数n和k的子集问题的代码。n表示学生总数,k表示我希望从n中获得的学生数量。代码试图给出从n个学生中抽取k个学生的可能组合数

def subset(n, k): 
    if k == 0:
        return 1
    if n == k:
        return 1
    else:
        return subset(n-1, k-1) + subset(n-1, k)

我理解递归调用的第一部分,但理解+子集(n-1,k)部分有困难。有人能给我解释一下吗?

这更像是一个数学问题,而不是一个编程问题。你要做的是计算二项式系数,公式是

(n, k) = (n-1, k-1) + (n-1, k) with all (n, 0) and (n, n) having a value of 1.

请看完整的解释。可以看到递归解决方案。如果提到的链接无效,只需使用谷歌搜索即可。我怀疑你在维基百科上读过这篇文章后,会得到比这更好的解释。

递归是基于一个简单的观察,对此我将给出一个组合论证,解释为什么它是真的,而不是通过公式进行数学证明

无论何时从
n
中选择
k
元素,都有两种情况:

  • 您选择元素
    #n
  • 您没有选择元素
    #n
  • 由于这些事件是互斥的,因此组合总量由选择
    #n
    时的组合量和未选择
    #n
    时的组合量给出

    选择元素
    #n
    因为我们已经选择了一个元素,所以只需要选择另一个
    k-1
    元素。此外,既然我们已经决定了一个元素——关于它是否被包含——我们只需要考虑剩下的<代码> N-1 元素。 因此,用于选择元素
    #n
    的组合量如下所示:

        subset(n - 1, k - 1)
    
    不选择元素
    #n
    仍然有
    k
    元素可供选择,但由于我们已经对元素
    #n
    下了决心,因此只剩下
    n-1
    元素可供选择。因此:

        subset(n - 1, k)
    
    基本情况 递归使用了这样一个事实,即我们通常可以区分两种情况,元素
    n
    是该解决方案一部分的解决方案,以及元素
    n不是该解决方案一部分的解决方案

    然而,这种区分并不总是可以做到:

    • 选择所有元素时(对应于下面代码中的大小写
      n==k
    • 或者完全不选择任何元素时(对应于下面代码中的大小写
      k==0
    在这些情况下,只有一种解决方案,因此

    if k == 0:
        return 1
    if n == k:
        return 1
    
    确保它起作用 要做到这一点,我们需要说服自己(或证明)基本情况总是在某个时候发生

    让我们假设,
    n
    在某个点。由于根据我们的假设,
    n
    最初大于或等于
    k
    ,因此肯定存在
    n=k
    的某个点,因为
    n
    k
    一致减少,或者只有
    n
    减少了一个,即它如下所示

    这意味着,必须调用
    子集(n-1,k)
    ,才能发生
    n
    降低到
    k
    以下。然而,这是不可能的,因为我们在
    n=k
    上有一个基本情况,其中我们返回一个常量
    1

    我们得出结论,要么
    n
    在某一点上减少,使
    n=k
    ,要么一致减少
    k
    次,使
    k=0

    因此,基本情况有效。

    代码片段:

    if k == 0:
        return 1
    if n == k:
        return 1
    
    使用两个组合事实:

    nC0 = 1
    nCn = 1
    
    作为基本情况

    接下来,执行以下递归调用:

    return subset(n-1, k-1) + subset(n-1, k)
    
    将以下事实直接转换为代码:

    nCr = (n-1)C(k-1) + (n-1)Ck
    
    如果您难以理解上述公式的适用性,请继续阅读: 在nCr中,我们从n中选择r项。如果我们考虑任何特定的项目:< /P>,选择可以分为两个相互排斥的类。
    • 项目出现在r个所选项目中

      在这种情况下,我们必须从剩余的n-1项中选择剩余的r-1项。这可以在(n-1)C(k-1)中完成

    • 项目不会出现在r个所选项目中

      在这种情况下,我们必须从剩余的n-1项中选择所有r项,这些项可以(n-1)Ck方式完成


    我们把这两个加起来,因为我已经说过,这两个类是互斥的,因此它们共同构成了从n中选择r项的总方法。

    不过,我真的对递归感到困惑。