斐波那契數列指的是這樣一個數列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987........數組
這個數列從第3項開始,每一項都等於前兩項之和。緩存
根據第n項的值等於n-1和n-2的值之和這個特性,代碼以下:bash
public class Fibonacci {
public static int Fib(int N) {
if (N < 3)
return 1;
else
return Fib(N - 1) + Fib(N - 2);
}
public static void main(String[] args) {
int num = Fib(10);
System.out.println(num);
}
}
複製代碼
這種方法的最大缺陷就是重複計算的次數太多了,致使時間複雜度高
,好比當n=3時ui
1. Fib1(3)=Fib1(2)+Fib1(1)
2. 計算Fib1(1) 第一次計算
3. 計算Fib1(2) 第二次計算
4. 計算Fib1(2)+Fib1(1) 第三次計算
複製代碼
就須要計算三次,時間複雜度:O(2^N),空間複雜度:O(N)spa
因爲第一種方式重複計算的次數過多,爲了不咱們能夠創建一個相似於全局變量的數組來存儲已經計算出來的數列項,在每一次遞歸時直接取出來前兩個值,省去重複計算。代碼以下:code
public class FibArray {
public static int[] array = new int[20];
public static int Fib(int n) {
if (n <= 1)
return n;
if (array[n] != 0)
return array[n];
else
return array[n] = Fib(n - 1) + Fib(n - 2);
}
public static void main(String[] args) {
int num = Fib(10);
System.out.println(num);
}
}
複製代碼
此種方法至關於緩存了前面的值,很大程度的減少了第一種方法(遞歸實現斐波那契數列)的時間複雜度,缺點是須要另外開闢數組內存,數組的長度是固定的,不能動態調整。
時間複雜度:0(N), 空間複雜度:0(N)cdn
public class FibForEach {
public static int Fib(int n) {
int first = 1;
int second = 1;
int ret = 0;
for (int i = 3; i <= n; i++) {
ret = first + second;
first = second;
second = ret;
}
return second;
}
public static void main(String[] args) {
int num = Fib(10);
System.out.println(num);
}
}
複製代碼
循環的方式省去了數組這個不定的因素,優勢:時間複雜度和空間複雜度最低,並且可讀性高
時間複雜度:O(N)
空間複雜度:O(1)(建立了四個對象,是常數,因此可忽略不計)對象
斐波那契還存在一個通項公式: blog
在數值較大的時候是尤其方便的public class FibAll {
static double ROOT_OF_FIVE = Math.sqrt(5.0);
static double Fib(int n) {
return (Math.pow(((1 + ROOT_OF_FIVE) / 2.0), n) / ROOT_OF_FIVE
- Math.pow(((1 - ROOT_OF_FIVE) / 2.0), n) / ROOT_OF_FIVE);
}
public static void main(String[] args) {
double num = Fib(10);
System.out.println(num);
}
}
複製代碼