斐波那契算法花费多少时间来计算F(n)

时间:2016-12-02 12:33:06

标签: algorithm fibonacci

我正在阅读Skiena的“算法设计手册”一书中的“8.1.1斐波纳契数字递归”部分。

我无法理解本节的以下段落。

此算法花费多少时间来计算F(n)?由于Fn + 1 /Fn≈ φ=(1 +√5)/2≈1.61803,这意味着Fn> 1。 1.6 ^ N。由于我们的递归树有 只有0和1作为叶子,总结到如此大的数字意味着我们必须有 至少1.6n离开或程序调用!这个简陋的小程序需要指数时间才能运行!

任何人都可以从这一段解释我的以下问题。

  • 为什么Fn + 1 / Fn用于计算算法时间?
  • 为什么Fn> 1.6 ^ N
  • 我们如何获得1.6n离开或程序调用?

请举例说明为F(4)

2 个答案:

答案 0 :(得分:2)

这是我对我的问题的回答。 如果使用递归计算斐波纳契数,则计算时间为F(N)+F(N-1)+F(N-2)+...+F(1) = F(N+2)-2 = O(F(N+2)).
Binet's Formula证明F(N) nearly equal sqrt(1/5) * φ^N,此公式也证明了这一点。

  • F(k + 1)/ F(k)几乎等于φ。
  • 如果你检查小k,你可以证明F(k)> = 1.6 ^ k。

但我建议计算这个算法的斐波纳契数。

1。使用动态编程
Fibonacci Sequence可以计算动态编程,时间为O(N)。
很明显,因为存在关系F(N)= F(N-1)+ F(N-2)。

2。使用矩阵指数
实际上,( (1 1) (1 0) )^N = ( (F(N+2) F(N+1)) (F(N+1) F(N)) ).
如果使用逐算子逐算法,则可以计算其O(log N)的值,因此可以计算O(log(N))的F(N)。

总之,Binet的公式并不好,因为它使用浮点值,因此会导致精度误差。
我建议使用动态编程或矩阵指数可以解决这个问题。

答案 1 :(得分:2)

我在答案的第一部分从n切换到m。

F(m + 1)/ F(m)是用于获得F(m)的近似值而不是时间的比率。从m> = 1开始,随着m增加,比率F(m + 1)/ F(m)快速收敛于φ=(1 + sqrt(5))/ 2~ = 1.61803。这可以重写为F(m + 1)〜=φF(m)。然后F(m + 2)〜=φF(m + 1)〜=φ(φF(m))〜=φ^ 2 F(m),一般F(m + k)〜=φ^ k F(m),m> = 10的合理近似值,如本答案末尾的表中所示。该段然后突然跳跃到F(n)> 1.6 ^ n,仅在n> = 72时才为真。

段落然后解决递归树,它只涉及添加,并注意到递归树的叶节点只返回0(F(0))或1(F(1)),所以你至少需要1.6 ^ n(不是1.6n)叶节点(返回1的1.6 ^ n叶节点)以产生总和> = 1.6 ^ n。 (再次注意,F(n)> 1.6 ^ n仅对n> = 72)为真。

对于更快的算法,Lucas序列方法类似于通过平方方法的优化矩阵求幂。 64位无符号整数的最大值是fib(93)== 12200160415121876738(在下面的代码中需要7个循环)。

/* lucas sequence method */
uint64_t fib(uint64_t n) {
    uint64_t a, b, p, q, aq, qq;
    a = q = 1;
    b = p = 0;
    while(1){
        if (n & 1) {
            aq = a*q;
            a = b*q + aq + a*p;
            b = b*p + aq;
        }
        n >>= 1;
        if (n == 0)
            break;
        qq = q*q;
        q = p*q*2 + qq;
        p = p*p + qq;
    }
    return b;
}

使用F(100)作为测试用例与m(10,20,30,40)的值,来了解近似值F(m + k)〜=φ^ k F(m)的准确度。 )。

F(100)/(φ^90 F(10)) ~= 1.0000661
F(100)/(φ^80 F(20)) ~= 1.00000000437
F(100)/(φ^70 F(30)) ~= 1.000000000000289
F(100)/(φ^60 F(40)) ~= 1.0000000000000000191