【发布时间】:2019-10-22 02:15:26
【问题描述】:
我问自己是否可以及时计算出第 n 个斐波那契数 O(n) 或 O(1),为什么?
谁能解释一下?
【问题讨论】:
-
表示第n个斐波那契数的位数如何作为n的函数增长?
标签: algorithm time-complexity big-o fibonacci
我问自己是否可以及时计算出第 n 个斐波那契数 O(n) 或 O(1),为什么?
谁能解释一下?
【问题讨论】:
标签: algorithm time-complexity big-o fibonacci
是的。它被称为Binet's Formula,或者有时,错误地,De Moivre 公式(真正的 De Moivre 公式是 another,但 De Moivre 确实在 Binet 之前发现了 Binet 公式) , 并涉及黄金比例 Phi。这背后的数学推理(见链接)有点复杂,但可行:
虽然它是一个近似公式,但斐波那契数是整数——因此,一旦您达到足够高的精度(取决于 n),您就可以将 Binet 公式中的数字近似为最接近的值整数。
然而,精度取决于常数,所以你基本上有两个版本,一个是浮点数,一个是双精度数,第二个也以恒定时间运行,但速度稍慢。对于大 n,您将需要一个任意精度的数字库,并且它们的处理时间确实取决于所涉及的数字;正如@MattTimmermans 所观察到的,您最终可能会得到一个 O(log^2 n) 算法。这应该发生在足够大的 n 值上,无论如何你都会被大量库困住(但我需要对此进行测试以确定)。
否则,Binet 公式主要由两个取幂和一个除法组成(三个和和除以 2 可能可以忽略不计),而递归公式主要使用函数调用,而迭代公式使用循环。虽然第一个公式是 O(1),其他两个是 O(n),但实际时间更像 a、bn + c 和 dn + e,a、b、c、d 和 e 的值取决于硬件、编译器、实现等。对于现代 CPU,a 很可能不会比 b 或 d 大,这意味着 O(1) 公式应该几乎每个 n 都更快。但是迭代算法的大多数实现都以
开头if (n < 2) {
return n;
}
对于 n = 0 和 n = 1,这很可能更快。我相信 Binet 的公式对于任何超过个位数的 n 都更快。
【讨论】:
与其考虑递归方法,不如考虑自下而上构建序列,从 1+1 开始。
【讨论】:
f(n) = f(n-1) + f(n-2),这意味着每个调用都会额外递归两次,使其呈指数级。
Can one compute the nth Fibonacci number in time O(n) or O(1)?
haskell Prelude> :{ Prelude| fib :: Int -> Int Prelude| fib n = go n (0,1) Prelude| where Prelude| go n (a,b) | n == 0 = a Prelude| | otherwise = go (n-1) (b, a+b) Prelude| :} 请参阅:wiki.haskell.org/The_Fibonacci_sequence
您也可以像这样使用矩阵m:
1 1
1 0
并计算它的幂n。然后输出m^n[0,0]。
【讨论】:
Can one compute the nth Fibonacci number in time O(n) or O(1)?