每天一道算法题(30)——高效的求斐波拉契数列

         对于斐波拉契经典问题,我们都非常熟悉,通过递推公式F(n) = F(n - 1) + F(n - 2),我们可以在线性时间内求出第n项F(n),现在考虑斐波拉契的加强版,我们要求的项数n的范围为int范围内的非负整数,请设计一个高效算法,计算第n项F(n)。第一个斐波拉契数为F(0) = 1。给定一个非负整数,请返回斐波拉契数列的第n项,为了防止溢出,请将结果Mod 1000000007。

         或者,现在有一栋高楼,但是电梯却出了故障,无奈的你只能走楼梯上楼,根据你的腿长,你一次能走1级或2级楼梯,已知你要走n级楼梯才能走到你的目的楼层,请计算你走到目的楼层的方案数,由于楼很高,所以n的范围为int范围内的正整数。

给定楼梯总数n,请返回方案数。为了防止溢出,请返回结果Mod 1000000007的值。


1.递归    时间复杂度O(2^n)

[java] view plaincopy
  1. int f(int n){  
  2.     if(n == 1 || n == 2){  
  3.         return 1;  
  4.     }  
  5.     return f(n-1) + f(n-2);  
  6. }  

2.循环    时间复杂度O(n)

[java] view plaincopy
  1. public int f(int n) {  
  2.     // write code here  
  3.     int f0 = 1;  
  4.     int f1 = 1;  
  5.     int f2 = 0;  
  6.   
  7.     for(int i = 2; i < n; i++){  
  8.         f2 = f0 + f1;  
  9.         f0 = f1;  
  10.         f1 = f2;  
  11.     }  
  12.     return f2;  
  13. }  

3.矩阵求解    时间复杂度O(logn)

    斐波那契的递推公式可以表示成如下矩阵形式:

     根据矩阵的分治算法,可以在O(logn)时间内算出结果。

public class Fibonacci {
	static long[][] f = new long[][]{{0,1},{1,1}};  
	public int getNthNumber(int n) {  
	    if(n == 0)  
	        return 1;  
	    if(n == 1)  
	        return 1;  
	    f = pow(n,f);  
	      
	    return (int) (f[1][1]%1000000007);  
	}  
	  
	private long[][] pow(int n,long[][] f){//矩阵的幂函数 
	    if(n == 1)  
	        return f;            
	    if(n == 2)
	        return fun(f,f);   
	  
	    if((n&1)==0){//偶数  
	        f = pow(n/2,f);  
	        return fun(f, f);  
	    }
	    else 
	        return fun(pow(n/2,f),pow(n/2 + 1,f));   
	}  
	  
	private long[][] fun(long[][] f,long[][] m){  
	    long[][] temp = new long[2][2];  
	    temp[0][0] = (f[0][0]*m[0][0] + f[0][1]*m[1][0]);
	    temp[0][1] = (f[0][0]*m[0][1] + f[0][1]*m[1][1]);  
	    temp[1][0] = (f[1][0]*m[0][0] + f[1][1]*m[1][0]);  
	    temp[1][1] = (f[1][0]*m[0][1] + f[1][1]*m[1][1])%1000000007;  
	    return temp;  
	}  
}





原文地址:https://www.cnblogs.com/engineerLF/p/5392991.html