Time complexity Fibonacci序列的计算复杂性
我理解大O符号,但我不知道如何计算许多函数的大O符号。特别是,我一直在试图找出斐波那契序列的原始版本的计算复杂性:Time complexity Fibonacci序列的计算复杂性,time-complexity,big-o,complexity-theory,fibonacci,Time Complexity,Big O,Complexity Theory,Fibonacci,我理解大O符号,但我不知道如何计算许多函数的大O符号。特别是,我一直在试图找出斐波那契序列的原始版本的计算复杂性: int Fibonacci(int n) { if (n <= 1) return n; else return Fibonacci(n - 1) + Fibonacci(n - 2); } intfibonacci(intn) { 如果(n只需问问自己需要执行多少语句才能完成F(n) 对于F(1),答案是1(条件的第一部分)
int Fibonacci(int n)
{
if (n <= 1)
return n;
else
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
intfibonacci(intn)
{
如果(n只需问问自己需要执行多少语句才能完成F(n)
对于F(1)
,答案是1
(条件的第一部分)
对于F(n)
,答案是F(n-1)+F(n-2)
那么什么函数满足这些规则呢?请尝试(a>1):
an==a(n-1)+a(n-2)
除以a(n-2):
a2==a+1
求解a
,得到(1+sqrt(5))/2=1.6180339887
,否则称为
所以这需要指数时间。只要问问自己需要执行多少语句才能完成F(n)
对于F(1)
,答案是1
(条件的第一部分)
对于F(n)
,答案是F(n-1)+F(n-2)
那么什么函数满足这些规则呢?请尝试(a>1):
an==a(n-1)+a(n-2)
除以a(n-2):
a2==a+1
求解a
,得到(1+sqrt(5))/2=1.6180339887
,否则称为
因此它需要指数时间。您将计算Fib(n)
的时间函数建模为计算Fib(n-1)
的时间加上计算Fib(n-2)
的时间加上将它们相加的时间(O(1)
)。这是假设重复计算相同的Fib(n)
使用相同的时间-即不使用备忘录
T(n您将计算Fib(n)
的时间函数建模为计算Fib(n-1)
的时间加上计算Fib(n-2)
的时间加上将它们相加的时间(O(1)
)。这是假设重复计算相同的Fib(n)
使用相同的时间-即不使用备忘录
T(n它在下端以2^(n/2)
为界,在上端以2^n为界(如其他注释所述)。递归实现的一个有趣的事实是,它本身具有Fib(n)的严格渐近界。这些事实可以总结为:
T(n) = Ω(2^(n/2)) (lower bound)
T(n) = O(2^n) (upper bound)
T(n) = Θ(Fib(n)) (tight bound)
如果你愿意的话,可以使用它来进一步减少紧界限。它在下端的界限是2^(n/2)
,在上端的界限是2^n(如其他注释所述)。递归实现的一个有趣的事实是,它本身具有Fib(n)的紧渐近界限。这些事实可以总结如下:
T(n) = Ω(2^(n/2)) (lower bound)
T(n) = O(2^n) (upper bound)
T(n) = Θ(Fib(n)) (tight bound)
如果您愿意,可以使用its进一步减少紧界限。关于这一点有一个很好的讨论。在第5页,他们指出,如果您假设一个加法需要一个计算单位,那么计算Fib(N)所需的时间与Fib(N)的结果密切相关
因此,您可以直接跳到非常接近斐波那契级数的近似值:
Fib(N) = (1/sqrt(5)) * 1.618^(N+1) (approximately)
因此,假设naive算法在最坏情况下的性能是
O((1/sqrt(5)) * 1.618^(N+1)) = O(1.618^(N+1))
PS:如果你想了解更多信息,可以在维基百科上讨论over。这是一个非常好的讨论。在第5页,他们指出,如果你假设一个加法需要一个计算单位,那么计算Fib(N)所需的时间与Fib(N)的结果密切相关
因此,您可以直接跳到非常接近斐波那契级数的近似值:
Fib(N) = (1/sqrt(5)) * 1.618^(N+1) (approximately)
因此,假设naive算法在最坏情况下的性能是
O((1/sqrt(5)) * 1.618^(N+1)) = O(1.618^(N+1))
PS:如果您想了解更多信息,可以在Wikipedia上讨论over。好吧,根据我的说法,它是O(2^n)
,因为在这个函数中,只有递归需要相当长的时间(分而治之).我们看到,上述函数将在树中继续,直到我们达到F(n-(n-1))
水平,即F(1)
。因此,当我们记下在树的每个深度遇到的时间复杂性时,求和序列是:
1+2+4+.......(n-1)
= 1((2^n)-1)/(2-1)
=2^n -1
这是2^n[O(2^n)]
的顺序,根据我的说法,它是O(2^n)
因为在这个函数中,只有递归需要相当长的时间(分而治之)。我们看到,当我们达到F(n-(n-1))
即F(1)时,上面的函数将在树中继续,直到叶子接近
。因此,当我们记下在树的每个深度遇到的时间复杂性时,求和序列是:
1+2+4+.......(n-1)
= 1((2^n)-1)/(2-1)
=2^n -1
这是2^n[O(2^n)]
的顺序证明答案很好,但我总是要亲自做几次迭代才能真正说服自己。所以我在白板上画了一个小的调用树,开始计算节点。我将计数分为总节点、叶节点和内部节点。我得到的结果如下:
IN | OUT | TOT | LEAF | INT
1 | 1 | 1 | 1 | 0
2 | 1 | 1 | 1 | 0
3 | 2 | 3 | 2 | 1
4 | 3 | 5 | 3 | 2
5 | 5 | 9 | 5 | 4
6 | 8 | 15 | 8 | 7
7 | 13 | 25 | 13 | 12
8 | 21 | 41 | 21 | 20
9 | 34 | 67 | 34 | 33
10 | 55 | 109 | 55 | 54
立即跳出来的是叶节点的数量是fib(n)
。经过几次迭代后才注意到内部节点的数量是fib(n)-1
。因此,节点的总数是2*fib(n)-1
由于在对计算复杂度进行分类时,会删除系数,因此最终的答案是θ(fib(n))
证明答案很好,但我总是要亲自做几次迭代才能真正说服自己。所以我在白板上画了一个小的调用树,开始计算节点数。我将计数分为总节点数、叶节点数和内部节点数。我得到的结果如下:
IN | OUT | TOT | LEAF | INT
1 | 1 | 1 | 1 | 0
2 | 1 | 1 | 1 | 0
3 | 2 | 3 | 2 | 1
4 | 3 | 5 | 3 | 2
5 | 5 | 9 | 5 | 4
6 | 8 | 15 | 8 | 7
7 | 13 | 25 | 13 | 12
8 | 21 | 41 | 21 | 20
9 | 34 | 67 | 34 | 33
10 | 55 | 109 | 55 | 54
立即跳出来的是叶节点的数量是fib(n)
。经过几次迭代后才注意到内部节点的数量是fib(n)-1
。因此,节点的总数是2*fib(n)-1
m = log2(n) // your real input size
m = log2(n)
2^m = 2^log2(n) = n
T(m) = n steps = 2^m steps
n
(n-1) (n-2)
(n-2)(n-3) (n-3)(n-4) ...so on
i
0 n
1 (n-1) (n-2)
2 (n-2) (n-3) (n-3) (n-4)
3 (n-3)(n-4) (n-4)(n-5) (n-4)(n-5) (n-5)(n-6)
2^0=1 n
2^1=2 (n-1) (n-2)
2^2=4 (n-2) (n-3) (n-3) (n-4)
2^3=8 (n-3)(n-4) (n-4)(n-5) (n-4)(n-5) (n-5)(n-6) ..so on
2^i for ith level
i work
1 2^1
2 2^2
3 2^3..so on
2 (2 -> 1, 0)
4 (3 -> 2, 1) (2 -> 1, 0)
8 (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
14 (5 -> 4, 3) (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
(3 -> 2, 1) (2 -> 1, 0)
22 (6 -> 5, 4)
(5 -> 4, 3) (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
(3 -> 2, 1) (2 -> 1, 0)
(4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)