寫一個函數,輸入 n ,求斐波那契(Fibonacci)數列的第 n 項。斐波那契數列的定義如下:
F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契數列由 0 和 1 開始,之后的斐波那契數就是由之前的兩數相加而得出。
在沒有接觸動態規劃解法之前,首先想到的就是遞歸。通過遞歸 n-1 ,直到 n 為 0、1 的特值。
直接遞歸
- 原理: 把 f(n)f(n) 問題的計算拆分成 f(n-1)f(n?1) 和 f(n-2)f(n?2) 兩個子問題的計算,并遞歸,以 f(0)f(0) 和 f(1)f(1) 為終止條件。
- 缺點: 大量重復的遞歸計算,例如 f(n)f(n) 和 f(n - 1)f(n?1) 兩者向下遞歸需要 各自計算 f(n - 2)f(n?2) 的值。
func fib(_ n: Int) -> Int {
if (n == 0) {
return 0
}
if (n == 1) {
return 1
}
return fib(n-1) + fib(n-2)
}
好吧,如果你用這個代碼提交到力扣上,直接gg。這種方法太過耗時了。
。
樹中存在很多重復的節點,算法中存在很多重復的計算量。優化策略:我們可以將算好的結果緩存起來,如果下次碰到一樣的計算項時,我們先可以查找緩存。如果查不到在去計算。會大大的節省計算時間。
記憶化遞歸
我們可以使用O(n)的空間來存放計算的結果,每次計算可以查找到之前結果,不用重新計算。
func fib(_ n: Int) -> Int {
if (n == 0) {
return 0
}
if (n == 1) {
return 1
}
var cache = [Int](repeating: 0, count: n+1)
cache[1] = 1
for i in 2...n {
cache[i] = cache[i-1] + cache[i-2]
}
return cache[n]
}
動態規劃
我們也可以通過動態規劃來解決這道問題。目前留個坑,學完動態規劃在回來解決。