特别说明:本文参考学习于Java语言程序设计进阶篇—Y.Daniel Liang著一书
欢迎大家一起学习交流,希望程序的世界有你相伴
题目
给出下标index,找出斐波那契数列下标为index的值,斐波那契数列为: {1,1,2,3,5,8…},前两位为1,随后的值均为在它前面的两个数的和。
解法
方法1
利用斐波那契数列的构造原理,我们很容易写出如下的递归算法解决该问题
public static long fib1(int index) {
if (index == 0)
return 0;
else if (index == 1)
return 1;
else
return fib1(index - 1) + fib1(index - 2);
}
时间复杂度
令下标为n,假设T(n)表示找出fib1(n)的算法的复杂度,而c表示比较下标为0的数和下标为1的数耗费的常量时间,也就是说T(1)是c。因此
T(n)=T(n-1) + T(n-2) + c
<= 2*T(n-1) + c
<= 2*(2*T(n-2)+c) + c
= 2^2 *T(n-2) + 2c + c
...
= 2^(n-1) *T(1) + (n-1)c + ... + c
可以发现T(n) 的O(2^n)。
可改进点
这个算法的效率并不高,递归的fib1()方法中存在的问题在于冗余地调用同样参数的方法。例如,为了计算fib1(4),要调用fib1(3)和fib1(2)。为了计算fib1(3),要调用fib1(2)与fib1(1)。注意fib1(2)被调用多次。我们可以通过避免这样重复调用同样的参数的fib1方法来提高算法效率。注意,一个新的斐波那契数是通过对数列中的前两个数相加得到的。如果用两个变量f0和f1来存储前面两个数,那么可以通过将f0和f1相加立即获得新数f2。这样,我们可以通过构建斐波那契数列的同时,得到该题的高效率的解法。
方法2
public static long fib2(int index) {
long f0 = 0;
long f1 = 1;
long f2 = 1;
if (index == 0)
return f0;
else if (index == 1)
return f1;
else if (index == 2)
return f2;
for (int i = 3; i <= index; i++) {
f0 = f1;
f1 = f2;
f2 = f0 + f1;
}
return f2;
}
显然这样的算法的时间复杂度是O(n),这比方法1中的算法高效很多。