斐波那契數列第n項的三種求法
方法1:
利用遞迴方法,但是遞迴看似簡單但是無法處理較大的項數,時間複雜度為o(2^n)。
public class fib_遞迴 { /** * @param args */ public static void main(String[] args) { int n=10; System.out.println(fib(n)); } private static int fib(int n) { if(n==1 || n==2){ return 1; } return fib(n-1)+fib(n-2); } }
方法2:
利用f(n)=f(n-1)+f(n-2),這一遞推方程,不斷向後順序計算即可,時間複雜度為o(n)。
public class fib_dp { /** * @param args */ public static void main(String[] args) { int n=5; System.out.println(fib(n)); } private static int fib(int n) { if(n==1 || n==2){ return 1; } int sec=1;//第二項 int fir=1;//第一項 int temp=0;//臨時項 for (int i = 3; i <= n; i++) { temp=sec; sec=fir+sec; fir=temp; } return sec; } }
方法3:
f(n)=f(n-1)+f(n-2) 是二階遞推式,我們可以將它表示成二階矩陣的形式
(f(n),f(n-1))=(f(n-1),f(n-2))*(a,b|c,d) (注:(a,b|c,d)是一個二階矩陣,第一行為(a,b),第二行為(c,d))
因為f(1)=1,f(2)=1,f(3)=2,f(4)=3,帶入上述矩陣方程中可得a=1 , b=1 , c=1 , d=0。
所以(f(n),f(n-1))=(f(n-1),f(n-2))*(1,1|1,0)
要想計算f(n)
我們可以觀察一下遞推式:
(f(3),f(2))=(f(2),f(1))*(1,1|1,0)
(f(4),f(3))=(f(3),f(2))*(1,1|1,0)
.......
(f(n),f(n-1))=(f(n-1),f(n-2))*(1,1|1,0)
將上述等式左右兩邊相乘
得(f(n),f(n-1)) = (1,1) * [(1,1|1,0)^n-2]
所以求第n項值的問題就轉化為求矩陣冪的問題
public class fib快速冪 {
/**
* @param args
*/
public static void main(String[] args) {
int n=20;
System.out.println(fib(n));
}
private static int fib(int n) {
if(n<1)return 0;
if(n==1 || n==2){
return 1;
}
int base[][]={{1,1},{1,0}};
int res[][]=matrixp(base,n-2);
return res[0][0]+res[0][1];
}
private static int[][] matrixp(int[][] m, int n) {
int res[][]=new int[m.length][m[0].length];
for (int i = 0; i < res.length; i++) {
res[i][i]=1;
}
int temp[][]=m;
for (; n!=0; n>>=1) {
if((n&1)!=0){
res=muli(res,temp);
}
temp=muli(temp,temp);
}
return res;
}
private static int[][] muli(int[][] m1, int[][] m2) {
int r[][]=new int[m1.length][m2[0].length];
for (int i = 0; i < r.length; i++) {
for (int j = 0; j < r[0].length; j++) {
for (int k = 0; k < m2.length; k++) {
r[i][j]+=m1[i][k]*m2[k][j];
}
}
}
return r;
}
}