问题描述:
计算Fibonacci序列
分析:
有两种方法,
第一种实现起来相当那个简单,但是做了大量重复的计算,比如计算fib(3)需要计算fib(2)和fib(1),但是计算fib(2)的时候还要计算一遍fib(1),复杂度为指数级。
所以第二种实现采用从小到大的计算方式,没有重复的计算。
代码实现:
Poor performance
package c02;
/**
* @project: DataStructureAndAlgorithmAnalysis
* @filename: Fibonacci
* @version: 0.10
* @author: Jimmy Han
* @date: 21:52 2015/7/7
* @comment: Bad performance fibonacci
* @result: 89
*/
public class FibonacciBad {
public static void main(String[] args) {
System.out.println(fib(10));
}
public static long fib(int n){
if(n <= 1)
return n;
else
return fib(n -1) + fib(n - 2);
}
}
Good performance:
package c02;
/**
* @project: DataStructureAndAlgorithmAnalysis
* @filename: Fibonacci
* @version: 0.10
* @author: Jimmy Han
* @date: 22:30 2015/7/7
* @comment: Test Purpose
* @result:
*/
public class Fibonacci {
public static void main(String[] args) {
System.out.println(fib(10));
}
public static long fib(long n){
if(n < 2)
return n;
long f1 = 0;
long f2 = 1;
long res = 0;
for(long i = 2; i <= n; i++){
res = f1 + f2;
f1 = f2;
f2 = res;
}
return res;
}
}
经网友指出有log(n)复杂度方法,验证如下:
package c02;
/**
* @project: DataStructureAndAlgorithmAnalysis
* @filename: FibonacciBetter
* @version: 0.10
* @author: Jimmy Han
* @date: 23:29 2015/7/8
* @comment: Test Purpose
* @result:
*/
public class FibonacciBetter {
public static void main(String[] args) {
System.out.println(fib(10));
}
public static long fib(long n) {
//通过研究fibonacci序列的规律:
if (n ==0)
return 0;
if (n == 1 || n == 2)
return 1;
//如果n为奇数,则fib(n)为fib((n+1)/2)^2 + fib((n-1)/2)^2
//比如,fib(9) = fib(5)^2 + fib(4)^2
if (n % 2 == 1)
return fib((n+1)/2)*fib((n+1)/2) + fib((n-1)/2)*fib((n-1)/2);
//如果n为偶数,则fib(n)为fib(n/2)^2 + fib((n-2)/2)^2 + fib(n/2-1)*fib(n/2) + fib(n/2-2)*fib(n/2-1)
//比如,fib(10) = fib(5)^2 + fib(4)^2 + fib(4)*fib(5) + fib(3)*fib(4)
else
return fib(n/2)*fib(n/2) + fib((n-2)/2)*fib((n-2)/2) + fib(n/2-1)*fib(n/2) + fib(n/2-2)*fib(n/2-1);
}
}
结论:
方法3确实实现了O(logN)的复杂度,但是在实际测试中发现因为伴随大量的压栈操作,实际测试效果并不一定比方法2更快。当然可以通过把递归展开来降低运行时间,本人并没有进一步做测试,不过有一点可以确定,通过减少计算的数目,确实可以达到比方法2更快的速度。