【问题标题】:Running time T(n) of recursive function递归函数的运行时间T(n)
【发布时间】:2013-03-11 13:28:45
【问题描述】:

我正在尝试计算此函数的 T(n),而我得出的结果是 T(n) = T(n) + T(n) + O(1)。我有两个 T(n) 用于对函数 g() 的 2 次递归调用,然后是 O(1) 用于所有恒定时间操作,例如加法。我觉得我很遥远,所以任何帮助将不胜感激,我的数学背景不太好。

int g(int y) {
 if (y <= 0) {
  return 1;
 }
 else {
  return g(y - 1) + g(y - 2);
 }
}

【问题讨论】:

标签: c++ recursion time time-complexity fibonacci


【解决方案1】:

计算Fibonacci numberstime complexity 取决于所使用的算法。至少有 4 种算法可以计算它们(时间复杂度不同):

O(\phi^n)

首先我们提到我们可以通过查看递归斐波那契函数的call graph 来解决这个问题。

调用图实际上是一棵树。

我们可以将一切归结为找出这棵树有多少个节点。

F(n)的调用图中的节点数有根和F(n-1)的调用图中的节点数+F(n-2)的调用图中的节点数)。

我们将用 L(n) 表示 F(n) 中的节点数(您会看到字母 L 并非偶然)。

如上所述,L(n) = L(n-1) + L(n-2) + 1。

但是等等,还有更多!事实证明,这些是完全正确 Leonardo numbers 并且它们具有一般的封闭形式:

("a(n) is the number of nodes in the Fibonacci tree of order n."A001595)

O(n)

还有另一种算法涉及memoization,其复杂度为 O(n)(here is an exampleanother one)。这涉及将 T(n) 的结果存储在一个向量中,并逐渐计算 n=1 的 T(n) 直到所需的 n。

如果你想真正正确,这也不是 O(n),因为假设加法的数量成本是 O(1),但是......随着 F(n) 变大,添加两个斐波那契数的成本是 O(n)。你可以read more about this here,这是一个很好的阐述。所以,这个实现的实际复杂度是 O(n^2)。

O(1)

如果您使用arbitrary precision arithmeticsome smart rounding,还有另一种复杂度为 O(1) 的算法。它来自Binet's formula。对于 Binet 公式的证明,请参见第 1.3 节关于使用生成函数的page 13 here,或者,您可以找到eigendecomposition of the matrix,然后将其用于compute the nth power。 完成此操作后,您的封闭式公式将位于第 n 次幂矩阵的单元格之一中。

如果你想非常精确,它实际上是 O(log(n)),因为这是你用来计算 Binet 公式的 exponentiation by squaring(也称为 repeated squaring,二进制幂算法或二进制求幂)。

通常我们假设x^n 的取幂是O(1),但事实并非如此,它的乘法次数是O(log(n))。更准确地说,您必须考虑乘法的成本,这取决于所使用的multiplication algorithm

这是Binet的公式:

Fibonacci sequence looks in matrix form

这里是平方取幂:

2015 年 6 月 29 日更新

O(log(n))

还有另一种在 O(log(n)) 中计算斐波那契数的方法。 使用了两个身份

它们允许基于 F(n),F(n+1) 计算 F(2*n+1)F(2*n) 基于 F(n-1),F(n),F(n+1)。 该算法找到 nmost significant bit 并向下迭代到最低有效位,同时使用沿途的标识来计算斐波那契数。有一个algorithm here 的实现。这两个恒等式可以在quadratic fieldℚ(√5) 中导出(如上一个链接),也可以从上述矩阵的 n 次和 2n 次方导出(参见第 2.5 节标题为“矩阵方法” on page 23 of “计算算法 J. L. Holloway 的 Fibonacci Numbers Quickly"

【讨论】:

  • 非常干净简洁,+1
【解决方案2】:

递归关系如下:

T(n) = T(n-1) + T(n-2) + O(1)

这不适合主定理下的任何情况,因为您的方程式中没有 T(n/b) 形式的项。

因此,我们不得不采取一种有点奇怪的方法:

由于T(n-1),根据上面的定义,等于T(n-3) + T(n-2) + O(1),你可以把T(n)写成:

T(n) = 2T(n-2) + T(n-3) + 2*O(1)

由于 T(n-2) = T(n-3) + T(n-4) + O(1),我们可以进一步简化 T(n) 为:

T(n) = 3T(n-3) + 2T(n-4) + 3*O(1)

现在,我们应该开始看到一种模式,但让我们更进一步了解它。由于 T(n-3) = T(n-4) + T(n-5) + O(1):

T(n) = 5T(n-4) + 3T(n-5) + 4*O(1)

第一项的系数遵循斐波那契数列的模式。在下一轮中,我们将以 8T(n-5) 作为前导项。第二项也遵循斐波那契数列,因为在下一轮我们将有 5T(n-6)。第三项与 n 一样增长。

所以,由于 T(1) 只是 O(1),你最终会得到:

T(n) = x*O(1) + y*O(1) + n*O(1) 其中 x 是斐波那契数列中的第 n 项,y 是斐波那契数列中的第 (n-1) 项。

查看前导项,您可以看到我们的大 O 分析基本上就是根据 n 计算 x 的公式。

您可以在此处查看该公式:http://www.askamathematician.com/2011/04/q-is-there-a-formula-to-find-the-nth-term-in-the-fibonacci-sequence/

当您应用大 O 分析时,这将归结为以下几点: O(1.6^n)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 2019-03-23
    • 2016-04-23
    相关资源
    最近更新 更多