2.9 Fibonacci數列
阿新 • • 發佈:2020-11-20
2.9 Fibonacci數列
序言
先看一下優美的Fibonacci螺旋曲線
畫圖程式碼
import turtle
a, b = 0, 1
while a < 1000:
turtle.circle(a, 90)
a, b = b, a+b
基礎問題
解法
-
解法1 : 遞迴
-
解法2 : 求解通項公式
解法2 : 求解通項公式
\[F(n) = F(n-1) + F(n-2) \]由此得到特徵方程:
\[x^2 = x + 1 \]有根
\[x_1 = \frac{1+\sqrt{5}}{2},x_2 = \frac{1-\sqrt{5}}{2} \]所以存在A,B使得
代入\(F(0) = 0,f(1) = 1\)得\(A=\frac{\sqrt{5}}{5},B=-\frac{\sqrt{5}}{5}\)
\[F(n) = \frac{\sqrt{5}}{5} * (\frac{1+\ sqrt{5}}{2})^n - \frac{\sqrt{5}}{5} * (\frac{1-\sqrt{5}}{2})^n \] -
解法3 : 分治策略
-
解法4 : 動態規劃
// 2.9 Fibonacci 數列 // import java.util.Math; class Test{ public static void main(String[] args) { /** ## 基礎問題 F(n) = 0 , if n==0 1 , if n==1 F(n-1) + F(n-1) , if n>1 > 解法 - 解法1 : 遞迴 - 解法2 : 求解通項公式 - 解法3 : 分治策略 - 解法4 : 動態規劃 ## 拓展問題 */ System.out.println(Fib1(10)); System.out.println((int)Fib2(10)); System.out.println(Fib3(10)); System.out.println(Fib4(10)); System.out.println(Fib5(10)); } /** 解法1 : 遞迴 */ public static int Fib1(int n){ if(n<=0) return 0; else if(n==1) return 1; else return Fib1(n-1) + Fib1(n-2); } /** 解法2 : 求解通項公式 $$F(n) = F(n-1) + F(n-2)$$ 由此得到特徵方程: $$x^2 = x + 1$$ 有根 $$x_1 = \frac{1+\sqrt{5}}{2},x_2 = \frac{1-\sqrt{5}}{2}$$ 所以存在A,B使得 $$F(n) = A * (\frac{1+\frac{5}}{2})^n + B*(\frac{1-\sqrt{5}}{2})^n$$ 代入$F(0) = 0,f(1) = 1$得$A=\frac{\sqrt{5}}{5},B=-\frac{\sqrt{5}}{5}$ $$F(n) = \frac{\sqrt{5}}{5} * (\frac{1+\frac{5}}{2})^n - \frac{\sqrt{5}}{5} * (\frac{1-\sqrt{5}}{2})^n$$ 通過公式,我們可以在O(1)時間複雜度求得,但是引入了無理數,所以不能保證結果的精度 */ public static double Fib2(int n){ return Math.sqrt(5.0)/5.0*Math.pow((1.0+Math.sqrt(5.0))/2.0,n) - Math.sqrt(5.0)/5.0*Math.pow((1.0-Math.sqrt(5.0))/2.0,n); } /** 解法3 : 分治策略 矩陣 */ public static int Fib3(int N){ if (N <= 1) return N; int[][] A = new int[][]{{1, 1}, {1, 0}}; matrixPower(A, N-1); return A[0][0]; } public static void matrixPower(int[][] A, int N) { if (N <= 1) { return; } matrixPower(A, N/2); multiply(A, A); int[][] B = new int[][]{{1, 1}, {1, 0}}; if (N%2 != 0) { multiply(A, B); } } public static void multiply(int[][] A, int[][] B) { int x = A[0][0] * B[0][0] + A[0][1] * B[1][0]; int y = A[0][0] * B[0][1] + A[0][1] * B[1][1]; int z = A[1][0] * B[0][0] + A[1][1] * B[1][0]; int w = A[1][0] * B[0][1] + A[1][1] * B[1][1]; A[0][0] = x; A[0][1] = y; A[1][0] = z; A[1][1] = w; } /** 解法4 : 動態規劃 */ public static int Fib4(int n){ int[] dp = new int[n+1]; dp[0] = 0; dp[1] = 1; for(int i =2;i<= n;i++) dp[i] = dp[i-1] + dp[i-2]; return dp[n]; } /** 解法4.2 : 動態規劃優化 */ public static int Fib5(int n){ int a = 0; int b = 1; int c = 0; for(int i = 2;i<=n;i++){ c=a+b; a = b; b=c; } return c; } }
拓展問題
假設\(A(0) = 1,A(1) = 2,A(2) = 2\),對於\(n>2\),都有\(A(k) = A(k-1) + A(k-2) + A(k-3)\)
1,對於任何一個n,如何計算出\(A(n)\)
2,對於n非常大的狀況,比如\(n=2^{60}\),如何計算\(A(n) mod N (M < 100000)\)呢?
答案
利用上述優化的dp