求斐波那契數列的第n項

問題描述:斐波那契數列是這樣的一個數列,1,1,2,3,5,8,..,即前兩項都是1,後面每一項都是其前面兩項的和。

              現在要你求出該數列的第n項。

分析:該問題是一個經典的數列問題,相信大家在很多語言的教科書上都碰到過這個練習題目。這裏我給大家總結了三種經典解法,並對這三個方法進行了對比。

         解法一:遞歸算法。很多教科書上都用這個題作爲函數遞歸知識點講解的例題,我們可以將每一個項的求法表達爲這樣一個式子:

                    f(n)=f(n-1)+f(n-2),f(1)=1,f(2)=1,可以看出,可以採用遞歸算法求解。

         解法二:循環求法。我們可以從第1項開始,一直求到第n項,即可,一個循環可以做到,時間複雜度爲O(n).

         解法三:矩陣鏈乘法。如果線性代數學的好的話,可以想出這樣一種解法,

                    

                         同樣可以採用遞歸的算法求解,時間複雜度爲O(logn).

           三種解法對比:解法一編程最簡單,但是效率最低,因爲這種遞歸算法求解時,會重複求解子問題。如下圖示:

                               

                                  這樣就看出來吧!另外如果n很大的話,遞歸的層數很大,會消耗系統大量的時間和資源。

                               解法二避免了重複求解子問題,線性時間即可求出,值得采用。

                               解法三效率最高,但是編程特別複雜,在有些情況下,很合適使用,但就本題目來說,推薦解法二。

    針對上述三種解法,我給出了詳細的Java代碼,讀者可以參考:

import java.util.*;
public class Main {
    public static int f1(int n){                     //方法一:遞歸算法,自底向上
    	if(n<=2)return 1;                            //如果是求前兩項,直接返回就可
    	else return f1(n-1)+f1(n-2);
    }
    public static int f2(int n){                     //方法二:循環算法,自上而下
    	if(n<=2)return 1;                            //如果是求前兩項,直接返回就可
    	int a1=1,a2=1,a3;
    	for(int i=3;i<=n;i++)
    		{
    		  a3=a1+a2;
    		  a1=a2;
    	      a2=a3;
    		}
    	return a2;
    }
    public static int[][] f3(int n){                 //方法三:矩陣鏈相乘算法,採用遞歸實現
    	int a[][]={{1,1},{1,0}};                     //定義基矩陣
    	int b[][];                                   //存儲子方法的結果
    	int c[][]=new int[2][2];                     //存儲最後計算結果
    	int d[][]=new int[2][2];                     //存儲中間計算結果
    	if((n)<=1)return  a;                         //如果次方小等於1直接返回
    	else if((n) %2==1)
    		     {b=f3((n-1)/2);
    	        
    		     d[0][0]=b[0][0]*b[0][0]+b[0][1]*b[1][0];
    		     d[0][1]=b[0][0]*b[0][1]+b[0][1]*b[1][1];
    		     d[1][0]=b[1][0]*b[0][0]+b[1][1]*b[1][0];
    		     d[1][1]=b[1][0]*b[0][1]+b[1][1]*b[1][1];
    		    
    		     c[0][0]=d[0][0]*a[0][0]+d[0][1]*a[1][0];
    		     c[0][1]=d[0][0]*a[0][1]+d[0][1]*a[1][1];
    		     c[1][0]=d[1][0]*a[0][0]+d[1][1]*a[1][0];
    		     c[1][1]=d[1][0]*a[0][1]+d[1][1]*a[1][1];
    		     
    	        }
    	else  {
    		 b=f3((n)/2);

    		 c[0][0]=b[0][0]*b[0][0]+b[0][1]*b[1][0];
		     c[0][1]=b[0][0]*b[0][1]+b[0][1]*b[1][1];
		     c[1][0]=b[1][0]*b[0][0]+b[1][1]*b[1][0];
		     c[1][1]=b[1][0]*b[0][1]+b[1][1]*b[1][1];
    	}
    	return c;
    }
	public static void main(String[] args) {
		// TODO 自動生成的方法存根
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        System.out.println("方法一:"+f1(n));
        System.out.println("方法二:"+f2(n));
        int a[][]=f3(n-1);                            //因爲是要求矩陣{{1,0},{1,0}}的n-1次方
        System.out.println("方法三:"+a[0][0]);
        
	}

}

輸出結果爲:

10
方法一:55
方法二:55
方法三:55



發佈了70 篇原創文章 · 獲贊 17 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章