動態(tài)規(guī)劃(Dynamic Programming)

本文素材來自視頻,請自備梯子觀看:What Is Dynamic Programming and How To Use It

Dynamic Programming:動態(tài)規(guī)劃分為如下幾步:

  1. 將復雜問題拆分成多個較簡單的子問題
  2. 對每個子問題只計算一次,然后使用數(shù)據(jù)結構(數(shù)組,字典等)在內存中存儲計算結果
  3. 子問題的計算結果按照一定規(guī)則進行排序(如,基于輸入?yún)?shù))
  4. 當需要再次運算子問題時直接使用已存儲的計算結果而非再次運算以提升求解性能

這種存儲計算結果以備再次使用稱之為:Memoization(這個詞,不知道怎么翻譯好)

以斐波那契數(shù)列為例來說明:

1、使用遞歸實現(xiàn):

def fib(n):
    if n < 1:
        raise ValueError('參數(shù)n必須為大于0的整數(shù)')
    if n == 1 or n == 2:
        return 1
    return fib(n-2)+fib(n-1)

這種方法是經典的遞歸運算。以fib(5)為例,整個求解過程可以拆分為:


圖片來自Youtube

我們可以看出,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('參數(shù)n必須為大于0的整數(shù)')
    if type(temp_dict) is not dict
        raise TypeError('參數(shù)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

圖片來自Youtube

優(yōu)化后,時間復雜度降為O(n)。優(yōu)化后的算法依然使用了遞歸,當參數(shù)較大時(如,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('參數(shù)n必須為大于0的整數(shù)')
    if type(temp_list) is not list:
        raise TypeError('參數(shù)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]
圖片來自Youtube

改進之后的算法不再使用遞歸,時間復雜度依然是O(n)。


對以上三種實現(xià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上看到這段視頻,就翻譯整理下來與大家共享。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容