費波那契數列(意大利語:Successione di Fibonacci),又譯費波拿契數、斐波那契數列、費氏數列、黃金分割數列。php
用文字來講,就是費波那契數列由0和1開始,以後的費波那契係數就由以前的兩數相加。首幾個費波那契係數是(OEIS A000045):算法
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,………………緩存
特別指出:0不是第一項,而是第零項。數據結構
(以上來自維基百科)函數
求解Fibonacci數列用java的遞歸很簡單:遞歸
public static long fibonacci(int n)
{
if(n == 0 || n == 1)
{
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}ip
但用遞歸求解的效率幾乎是沒法容忍的,當n爲50是,估計須要好幾分鐘,由於每遞歸調用一次fibonacci()函數,都會從新計算fibonacci(n - 1)和fibonacci(n - 2),這樣有不少數都是重複計算的,一個比較簡單的方法就是用一個數據結構將計算後的值緩存起來,ci
求解時先從緩存裏面拿數據,沒有的話再計算並將計算後的結果加到緩存裏面,這樣就避免了不少重複計算。下面是用HashMap將數據緩存的例子:get
private static HashMap<Integer, Long> hashMap = new HashMap<Integer, Long>();
private static long value;
public static long effectFibonacci(int n)
{
if(n == 0 || n == 1)
{
return 1;
}
if(hashMap.containsKey(n))
{
return hashMap.get(n);
}
else
{
value = effectFibonacci(n - 1) + effectFibonacci(n - 2);
hashMap.put(n, value);
}
return value;
}
這個算法跟上一個的效率相比有了很大的提升,當n = 1500時,花費的時間大約是 3082077 microseconds,而用上一個遞歸直接算,不知何年才能得出結果。
還有一種求解Fibonacci問題的方法就是利用動態規劃算法,動態規劃算法是將一個較大的問題分解爲若干類似子問題,求解子問題而後合併並獲得原問題的解,動態規劃算法適用於有重疊子問題和最優子結構性質的問題,重疊子問題即原問題可分解爲若干的求解算法類似的子問題,最優子結構就是局部最優致使全局最優,即可以將子問題的解合併後獲得原問題的解,這跟貪心算法類似。下面是用動態規劃算法求解Fibonacci數列問題:
public static long bestFinabocci(int n)
{
long previous = 1, next = 1;
long tmp = 2;
for (int i = 2; i <= n; i++)
{
tmp = previous + next; //從2開始,每個後面的數都是前面兩個數之和
previous = next;
next = tmp;
}
return tmp;
}
跟上一個使用遞歸緩存求解,動態規劃算法在效率上有了很大的提升,一樣當 n = 1500是,遞歸緩存花費的時間大約是 3082077 microseconds,而動態規劃花費的時間大約是 40410 microseconds。
由上面的實驗來看,在遞歸的問題上,最好使用循環代替遞歸,不得不用到遞歸時,最好將數據緩存起來避免重複計算,不要直接調用遞歸函數。