問題描述:斐波那契數列是這樣的一個數列,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代碼,讀者可以參考:
1 import java.util.*; 2 public class Main { 3 public static int f1(int n){ //方法一:遞歸算法,自底向上 4 if(n<=2)return 1; //如果是求前兩項,直接返回就可 5 else return f1(n-1)+f1(n-2); 6 } 7 public static int f2(int n){ //方法二:循環算法,自上而下 8 if(n<=2)return 1; //如果是求前兩項,直接返回就可 9 int a1=1,a2=1,a3; 10 for(int i=3;i<=n;i++) 11 { 12 a3=a1+a2; 13 a1=a2; 14 a2=a3; 15 } 16 return a2; 17 } 18 public static int[][] f3(int n){ //方法三:矩陣鏈相乘算法,采用遞歸實現 19 int a[][]={{1,1},{1,0}}; //定義基矩陣 20 int b[][]; //存儲子方法的結果 21 int c[][]=new int[2][2]; //存儲最后計算結果 22 int d[][]=new int[2][2]; //存儲中間計算結果 23 if((n)<=1)return a; //如果次方小等於1直接返回 24 else if((n) %2==1) 25 {b=f3((n-1)/2); 26 27 d[0][0]=b[0][0]*b[0][0]+b[0][1]*b[1][0]; 28 d[0][1]=b[0][0]*b[0][1]+b[0][1]*b[1][1]; 29 d[1][0]=b[1][0]*b[0][0]+b[1][1]*b[1][0]; 30 d[1][1]=b[1][0]*b[0][1]+b[1][1]*b[1][1]; 31 32 c[0][0]=d[0][0]*a[0][0]+d[0][1]*a[1][0]; 33 c[0][1]=d[0][0]*a[0][1]+d[0][1]*a[1][1]; 34 c[1][0]=d[1][0]*a[0][0]+d[1][1]*a[1][0]; 35 c[1][1]=d[1][0]*a[0][1]+d[1][1]*a[1][1]; 36 37 } 38 else { 39 b=f3((n)/2); 40 41 c[0][0]=b[0][0]*b[0][0]+b[0][1]*b[1][0]; 42 c[0][1]=b[0][0]*b[0][1]+b[0][1]*b[1][1]; 43 c[1][0]=b[1][0]*b[0][0]+b[1][1]*b[1][0]; 44 c[1][1]=b[1][0]*b[0][1]+b[1][1]*b[1][1]; 45 } 46 return c; 47 } 48 public static void main(String[] args) { 49 // TODO 自動生成的方法存根 50 Scanner scan=new Scanner(System.in); 51 int n=scan.nextInt(); 52 System.out.println("方法一:"+f1(n)); 53 System.out.println("方法二:"+f2(n)); 54 int a[][]=f3(n-1); //因為是要求矩陣{{1,0},{1,0}}的n-1次方 55 System.out.println("方法三:"+a[0][0]); 56 57 } 58 59 }
輸出結果為:
10
方法一:55
方法二:55
方法三:55