【问题标题】:What is the runtime of this algorithm? (Recursive Pascal's triangle)这个算法的运行时间是多少? (递归帕斯卡三角)
【发布时间】:2014-03-01 13:13:09
【问题描述】:

给定以下函数:

Function f(n,m)
   if n == 0 or m == 0: return 1
   return f(n-1, m) + f(n, m-1)

f 的运行时复杂度是多少?我知道如何快速而肮脏地做到这一点,但是如何正确地描述它呢?是O(2^(m*n))吗?

【问题讨论】:

  • 你确定不是 2^(m+n)?
  • @RonTeller - 大 O 表示法忽略常量,所以如果运行时实际上是 2^(m+n) +1 或类似的东西,在大 O 中它仍然是 O(2^(m+ n))。
  • @RonTeller - 你是对的。 blubb 得到了正确的答案。
  • @amink - 我认为它只是一个深度为 min(m,n) 的完整二叉树。之后,树变得更加稀疏。最长的分支长度为 m + n。
  • 此链接可能会回答您的问题:math.stackexchange.com/questions/80582/…

标签: algorithm recursion big-o


【解决方案1】:

这是帕斯卡三角形的一个例子:每个元素都是它上面两个元素的和,边都是一。

所以f(n, m) = (n + m)! / (n! . m!)

现在要知道计算f(n, m) 需要调用f 的次数,您可以构造一个修改后的帕斯卡三角形:考虑1 + sum(调用本身加上两个递归电话)。

画出修改后的三角形,你会很快说服自己这正是2.f(n, m) - 1

您可以从斯特林近似中获得二项式系数的渐近行为。 http://en.wikipedia.org/wiki/Binomial_coefficient#Bounds_and_asymptotic_formulas

f(n, m) ~ (n + m)^(n + m) / (n^n . m^m)

【讨论】:

    【解决方案2】:

    f(n, m) 的运行时在O(f(n, m)) 中。这很容易通过以下观察得到验证:

    Function g(n, m):
        if n=0 or m=0: return 1
        return g(n-1, m) + g(n, m-1) + 1
    

    函数f 的调用频率与g 相同。此外,函数g 被准确地调用g(n, m) 次以评估g(n, m) 的结果。同样,函数f 被精确调用g(n, m) = 2*f(n, m)-1 次以评估f(n, m) 的结果。

    正如@Yves Daoust 在他的回答f(n, m) = (n + m)!/(n!*m!) 中指出的那样,因此对于f,您将获得O((n+m)!/(n!*m!)) 的非递归运行时。

    【讨论】:

    • 不确定第二部分:假设n=10 m=1,您的函数返回2(应该是2*f),而原始函数将返回11
    • 现在它会返回3,它仍然关闭
    • @RonTeller:我修改了我的答案。现在应该是正确的。
    【解决方案3】:

    理解递归函数

    f(n, 0) = 1
    f(0, m) = 1
    f(n, m) = f(n - 1, m) + f(n, m - 1)
    

    在我看来,这些值就像 Pascal triangle

       n 0  1  2  3  4 ..
     m
    
     0   1  1  1  1  1 ..
     1   1  2  3  4
     2   1  3  6
     3   1  4     .
     4   1           .
     .   .
     .   .
    

    求解递归方程

    帕斯卡三角形的值可以表示为binomial coefficients。平移坐标得到 f 的解:

    f(n, m) = (n + m) 
              (  m  )
            = (n + m)! / (m! (n + m - m)!) 
            = (n + m)! / (n! m!)
    

    这是一个很好的术语,在参数 n 和 m 中都是对称的。 (最终任期首先由@Yves Daoust 在本次讨论中给出)

    帕斯卡法则

    利用二项式系数的对称性和Pascal's Rule可以推导出f的递归方程

    f(n, m) = (n + m)
              (  n  )
            = (n + m)
              (  m  )
            = ((n + m) - 1) + ((n + m) - 1)
              (      m    )   (    m - 1  )
            = ((n - 1) + m) + (n + (m - 1))
              (     m     )   (    m      )
            = f(n - 1, m) + f(n, m - 1)
    

    确定调用次数

    “f 的调用次数”计算函数 F 和 f 类似,我们只需要将 f 本身的调用和两个递归调用相加即可:

    F(0, m) = F(n, 0) = 1, otherwise
    
    F(n, m) = 1 + F(n - 1, m) + F(n, m - 1)
    

    (首先由@blubb 在本次讨论中给出)。

    了解调用次数函数

    如果我们把它写下来,我们会得到另一个三角形方案:

     1  1  1  1  1 ..
     1  3  5  7
     1  5 11
     1  7     .
     1           .
     .
     .
    

    逐个比较三角形的值,猜一猜

    F(n, m) = 2 f(n, m) - 1  (*)
    

    (@blubb 在本次讨论中首先提出的结果)

    证明

    我们得到

    F(0, m) = 2 f(0, m) - 1  ; using (*)
            = 1              ; yields boundary condition for F 
    
    F(n, 0) = 2 f(n, 0) - 1 
            = 1
    

    应该如此并检查 else 子句,我们看到

    F(n, m) = 2 f(n, m) - 1                                   ; assumption
            = 2 ( f(n - 1, m) + f(n, m - 1) ) - 1             ; definition f
            = 1 + (2 f(n - 1, m) - 1) + (2 f(n, m - 1) - 1)   ; algebra
            = 1 + F(n - 1, m) + F(n, m - 1)                   ; 2 * assumption
    

    因此,如果我们使用 (*) 和 f 的 else 子句,则 F 的 else 子句结果。

    由于有限差分方程和 F 的起始条件成立,我们知道它是 F(解的唯一性)。

    估计调用次数的渐近行为

    现在计算/估计 F 的值(即算法的运行时间)。

    作为

    F = 2 f - 1
    

    我们看到了

    O(F) = O(f).
    

    所以这个算法的运行时间是

    O( (n + m)! / (n! m!) )
    

    (@Yves Daoust 在本次讨论中首先给出的结果)

    近似运行时

    使用Stirling approximation

    n! ~= sqrt(2 pi n) (n / e)^n
    

    无需难以计算阶乘即可获得表格。一个得到

    f(n, m) ~= 1/(2 pi) sqrt((n+m) / (n m)) [(n + m)^(n + m)] / (n^n m^m)
    

    从而到达

    O( sqrt((n + m) / (n m)) [(n + m)^(n + m)] / (n^n m^m) )
    

    (@Yves Daoust 在本次讨论中首次建议使用斯特林公式)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      相关资源
      最近更新 更多