動態程式設計(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動態程式設計---動態代理Java程式設計
- 動態程式設計之classloader程式設計
- Java安全之Javassist動態程式設計Java程式設計
- ABAP 動態程式設計-FIELD-SYMBOLS程式設計Symbol
- ABAP動態程式設計-DESCRIBE FIELD程式設計
- C# 4.0中的動態型別和動態程式設計C#型別程式設計
- JAVA_動態代理AOP切面程式設計Java程式設計
- 設計模式:動態代理設計模式
- 設計模式_JAVA動態代理設計模式設計模式Java
- 程式設計模式-表驅動程式設計程式設計設計模式
- 好程式設計師分享MyBatis之動態SQL語句程式設計師MyBatisSQL
- Windows下的VC++動態連結庫程式設計WindowsC++程式設計
- WebClass實現動態WEB程式設計之理論篇 (轉)Web程式設計
- Java中的超程式設計與動態代理技術Java程式設計
- Android程式設計師必會技能—執行時動態生成類—之動態代理Android程式設計師
- Android程式設計師必會技能---執行時動態生成類---之動態代理Android程式設計師
- 動態表單儲存設計
- 動態表單後端設計後端
- 好程式設計師Java分享Mybatis必會的動態SQL程式設計師JavaMyBatisSQL
- .NET Core 實現動態代理做AOP(面向切面程式設計)程式設計
- Mybatis之介面程式設計--JAVA動態代理的最佳展現MyBatis程式設計Java
- 【阿里乾貨】動態的設計—過程驅動設計方案演化阿里
- [.net 物件導向程式設計進階] (20) 反射(Reflection)(上)利用反射技術實現動態程式設計物件程式設計反射
- 好程式設計師Java教程Java動態代理機制詳解程式設計師Java
- 端動態化方案詳細設計
- 玩轉PHP動態網頁設計PHP網頁
- 設計模式之cglib動態代理設計模式CGLib
- 事件驅動程式設計事件程式設計
- 動態計算rem的js程式碼REMJS
- 關於心態建設,程式設計和自學程式設計
- 鴻蒙程式設計江湖:ArkUI 的宣告式 UI 程式設計與狀態管理鴻蒙程式設計UI
- 設計模式(一) 動態代理初嘗試設計模式
- 10分鐘看懂動態代理設計模式設計模式
- 23種設計模式之——動態代理模式設計模式
- Java設計模式-之代理模式(動態代理)Java設計模式
- 使用者體驗之——動態設計
- 淺談應用動態體驗設計
- 小程式踩坑之旅–動態設定tabBartabBar