動態規劃法(一)從斐波那契數列談起
動態規劃法與分治方法
動態規劃(Dynamic Programming)與分治方法相似,都是透過組合子問題的解來求解原問題。不同的是,分治方法通常將問題劃分為互不相交的子問題,遞迴地求解子問題,再講它們的解組合起來,求出原問題的解。而動態規劃應用於子問題重疊的情況,即不用的子問題具有公共的子子問題。在這種情況下,如果採用分治演算法,則分治演算法會做許多不必要的工作,它會反覆地求解那些公共子子問題。對於動態規劃法,它對每個子子問題只求解一次,將其儲存在一個表格中,從而無需每次求解一個子子問題時都重新計算,避免了這種不必要的計算工作。
也就是說,動態規劃法與分治方法相比,是用空間來換時間,而時間上獲得的效益是很客觀的,這是一種典型的時空平衡(time-memory trade-off)的策略。通常,動態規劃法用來求解最最佳化問題(optimization problem),如斐波那契數列求值問題,鋼條切割問題,0-1揹包問題,矩陣鏈乘法問題,最長公共子序列(LCS)問題,最優二叉搜尋樹問題等。
一般情況下,動態規劃演算法的步驟如下:
刻畫一個最優解的結構特徵。
遞迴地定義最優解的值。
計算最優解的值,通常採用自底向上的方法。
利用計算出的資訊構造一個最優解。
接下來,我們將從斐波那契數列求值這個簡單的例子入手,來分析動態規劃法的具體步驟和優點。
斐波那契數列
斐波那契數列記為
具體寫出前幾項,就是:0,1,1,2,3,5,8,13,21,34,55,89,144,233......
接下來,我們將會採用遞迴法和動態規劃法來求解該數列的第n項,即f(n)的值。
遞迴法求解
首先,我們採用遞迴法來求解斐波那契數列的第n項
function fib(n) if n = 0 return 0 if n = 1 return 1 return fib(n − 1) + fib(n − 2)
分析上述虛擬碼,先是定義一個函式fib(n),用來計算斐波那契數列的第n項,當
在計算fib(5)時,fib(5)呼叫1次,fib(4)呼叫1次,fib(3)呼叫2次,fib(2)呼叫3次,fib(1)呼叫5次,fib(0)呼叫3次,一共呼叫函式fib()15次。由此,我們可以看到,在計算fib(5)時,存在多次重複的fib()函式的呼叫,當n增大時,重複呼叫的次數會急劇增加,如計算fib(50)時,fib(1)和fib(0)大約會被呼叫
我們用Python實現上述演算法,並計算f(38)的值及運算時間。Python程式碼如下:
import time# recursive methoddef rec_fib(n): if n輸出結果如下:
結果:39088169, 執行時間:22.93831205368042動態規劃法求解
在使用遞迴法來求解斐波那契數列的第n項時,我們看到了遞迴法的不足之處,因為遞迴法在使用過程中存在大量重複的函式呼叫,因此,效率很差,執行時間為指數時間。為了解決遞迴法存在的問題,我們可以嘗試動態規劃法,因為動態規劃法會在執行過程中,儲存上一個子問題的解,從而避免了重複求解子問題。對於求解斐波那契數列的第n項,我們在使用動態規劃法時,需要儲存f(n-1)和f(n-2)的值,犧牲一點記憶體,但是可以顯著地提升執行效率。
動態規劃法來求解斐波那契數列第n項的虛擬碼如下:function fib(n) var previousFib := 0, currentFib := 1 if n = 0 return 0 else if n = 1 return 1 repeat n−1 times var newFib := previousFib + currentFib previousFib := currentFib currentFib := newFib return currentFib在上述虛擬碼中,並沒有存在重複求解問題,只是在每次執行過程中,儲存上兩項的值,再利用公式
f(n)=f(n−1)+f(n−2) 來求解第n項的值。用Python實現上述過程,程式碼如下:import time# bottom up approach of Dynamic Programmingdef dp_fib(n): previousFib = 0 currentFib = 1 if n輸出結果如下:
結果:39088169, 執行時間:0.0顯然,使用動態規劃法來求解斐波那契數列第n項的執行效率是很高的,因為,該演算法的時間複雜度為多項式時間。
參考文獻
附錄
用遞迴法和動態規劃法來求解該數列的第n項,完整的Python程式碼如下:
# calculate nth item of Fibonacci Sequenceimport time# recursive methoddef rec_fib(n): if n輸出結果如下:
結果:39088169, 執行時間:22.42628264427185結果:39088169, 執行時間:0.0
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/756/viewspace-2802202/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python 實現 動態規劃 /斐波那契數列Python動態規劃
- 斐波那契數列
- 2024.9.6 leetcode 509 斐波那契數 (雜湊表/動態規劃)LeetCode動態規劃
- 從斐波那契數列談談程式碼的效能優化優化
- 斐波那契數列(Java)Java
- 斐波那契數列 (C#)C#
- PHP 與斐波那契數列PHP
- 斐波那契數列詳解
- 著名的斐波那契數列
- 斐波那契數
- js實現斐波那契數列JS
- 斐波那契數列演算法演算法
- 第十題:斐波那契數列
- [C103] 斐波那契數列
- 力扣之斐波那契數列力扣
- 劍指offer——斐波那契數列
- 斐波那契數列js 實現JS
- 斐波那契數列Ⅳ【矩陣乘法】矩陣
- 演算法一:斐波那契阿數列演算法
- 使用Python實現斐波那契數列Python
- 演算法(1)斐波那契數列演算法
- 斐波那契數列的來源——數兔子
- 斐波那契數列數與等冪和
- Leedcode-斐波那契數
- 509. 斐波那契數
- LeetCode 509[斐波那契數]LeetCode
- 一千位斐波那契數
- 每日一算 -- 斐波那契數列型別題型別
- 大數斐波那契數列的演算法演算法
- js迭代器實現斐波那契數列JS
- offer通過--9斐波那契數列-2
- JavaScript 實現:輸出斐波那契數列JavaScript
- 斐波那契數列:7數5層魔法塔(3)
- 斐波那契數列:7數5層魔法塔(2)
- 斐波那契數列:7數5層魔法塔(5)
- 斐波那契數列:7數5層魔法塔(8)
- 斐波那契數列:7數5層魔法塔(13)
- 斐波那契數列:7數5層魔法塔(12)