動態程式設計(DynamicProgramming)
本文素材來自視訊,請自備梯子觀看:What Is Dynamic Programming and How To Use It
Dynamic Programming:動態程式設計分為如下幾步:
- 將複雜問題拆分成多個較簡單的子問題
- 對每個子問題只計算一次,然後使用資料結構(陣列,字典等)在記憶體中儲存計算結果
- 子問題的計算結果按照一定規則進行排序(如,基於輸入引數)
- 當需要再次運運算元問題時直接使用已儲存的計算結果而非再次運算以提升求解效能
這種儲存計算結果以備再次使用稱之為:Memoization(這個詞,不知道怎麼翻譯好)
以斐波那契數列為例來說明:
1、使用遞迴實現:
def fib(n):
if n < 1:
raise ValueError(`引數n必須為大於0的整數`)
if n == 1 or n == 2:
return 1
return fib(n-2)+fib(n-1)
這種方法是經典的遞迴運算。以fib(5)為例,整個求解過程可以拆分為:
我們可以看出,fib(2)被計算三次,fib(3)與fib(1)各被計算2次,時間複雜度為O(2^n)。
2、對遞迴進行改進
def fib_memory(n):
d = dict()
_fib_memory(n, d)
def _fib_memory(n, temp_dict):
if n < 1:
raise ValueError(`引數n必須為大於0的整數`)
if type(temp_dict) is not dict
raise TypeError(`引數temp_dict必須為dict型別`)
if n in temp_dict:
return temp_dict[n]
if n == 1 or n == 2:
result = 1
else:
result = fib_memory(n-1, temp_dict)+fib_memory(n-2, temp_dict)
temp_dict[n] = result
return result
優化後,時間複雜度降為O(n)。優化後的演算法依然使用了遞迴,當引數較大時(如,1000)會導致棧溢位:RecursionError: maximum recursion depth exceeded in comparison
3、脫離遞迴:
def fib_bottom_up(n):
l = [None]*(n+1)
return _fib_bottom_up(n, l)
def _fib_bottom_up(n, temp_list):
if n < 1:
raise ValueError(`引數n必須為大於0的整數`)
if type(temp_list) is not list:
raise TypeError(`引數temp_list必須為list型別`)
if temp_list[n] is not None:
return temp_list[n]
if n == 1 or n == 2:
return 1
temp_list[1] = 1
temp_list[2] = 1
for i in range(3, n+1):
temp_list[i] = temp_list[i-1]+temp_list[i-2]
return temp_list[n]
改進之後的演算法不再使用遞迴,時間複雜度依然是O(n)。
對以上三種實現編寫測試用例:
# coding=utf-8
import temp
import unittest
class TestDif(unittest.TestCase):
def test_fib_0_throw_value_error(self):
with self.assertRaises(ValueError):
temp.fib(0)
def test_fib_1_return_1(self):
result = temp.fib(1)
self.assertEqual(1, result)
def test_fib_10_return_false(self):
result = temp.fib(10)
self.assertFalse(result == 10)
def test_fib_memory_10_return_false(self):
result = temp.fib_memory(10)
self.assertNotEqual(result, 10)
def test_fib_bottom_up_1000_return_true(self):
result = temp.fib_bottom_up(1000)
print(result)
self.assertTrue(result > 100000)
if __name__ == "__main__":
unittest.main()
小結
無意中在Youtube上看到這段視訊,就翻譯整理下來與大家共享。
相關文章
- Java安全之Javassist動態程式設計Java程式設計
- JAVA_動態代理AOP切面程式設計Java程式設計
- 設計模式:動態代理設計模式
- Android程式設計師必會技能---執行時動態生成類---之動態代理Android程式設計師
- Android程式設計師必會技能—執行時動態生成類—之動態代理Android程式設計師
- 程式設計模式-表驅動程式設計程式設計設計模式
- 好程式設計師分享MyBatis之動態SQL語句程式設計師MyBatisSQL
- Java中的超程式設計與動態代理技術Java程式設計
- Mybatis之介面程式設計--JAVA動態代理的最佳展現MyBatis程式設計Java
- 好程式設計師Java分享Mybatis必會的動態SQL程式設計師JavaMyBatisSQL
- .NET Core 實現動態代理做AOP(面向切面程式設計)程式設計
- 動態表單後端設計後端
- 設計模式之cglib動態代理設計模式CGLib
- 動態表單儲存設計
- 好程式設計師Java教程Java動態代理機制詳解程式設計師Java
- 端動態化方案詳細設計
- 鴻蒙程式設計江湖:ArkUI 的宣告式 UI 程式設計與狀態管理鴻蒙程式設計UI
- 關於心態建設,程式設計和自學程式設計
- 小程式踩坑之旅--動態設定tabBartabBar
- 小程式踩坑之旅–動態設定tabBartabBar
- 核心動畫程式設計(一)動畫程式設計
- 核心動畫程式設計(二)動畫程式設計
- 物件導向程式設計和根本狀態物件程式設計
- 10分鐘看懂動態代理設計模式設計模式
- 設計模式(一) 動態代理初嘗試設計模式
- 23種設計模式之——動態代理模式設計模式
- 好程式設計師Java培訓分享Java動態代理機制詳解程式設計師Java
- 好程式設計師Java學習路線之Spring框架之動態代理程式設計師JavaSpring框架
- 【ACM程式設計】動態規劃 第二篇 LCS&LIS問題ACM程式設計動態規劃
- 好程式設計師大資料培訓分享Hive的靜態分割槽與動態分割槽程式設計師大資料Hive
- PHP動態網頁設計與網站架設pdfPHP網頁網站
- Unity應用架構設計(6)——設計動態資料集合ObservableListUnity應用架構
- shell程式設計之免互動程式設計
- 《程式設計師的自我修養》筆記(二)——裝載與動態連結程式設計師筆記
- php程式碼審計之——phpstorm動態除錯PHPORM除錯
- 複雜報表設計之動態報表
- Django:動態問卷系統的Model設計Django
- 如何設計和維護本地動態IP池?