1. 程式人生 > >LeetCode總結,動態規劃問題小結

LeetCode總結,動態規劃問題小結

一,參考一般書籍中的“動態規劃”講解

1、基本概念

動態規劃(Dynamic Programming)對於子問題重疊的情況特別有效,因為它將子問題的解儲存在表格中,當需要某個子問題的解時,直接取值即可,從而避免重複計算!
動態規劃是一種靈活的方法,不存在一種萬能的動態規劃演算法可以解決各類最優化問題(每種演算法都有它的缺陷)。所以除了要對基本概念和方法正確理解外,必須具體問題具體分析處理,用靈活的方法建立數學模型,用創造性的技巧去求解。

2、基本思想與策略

基本思想與分治法類似,也是將待求解的問題分解為若干個子問題(階段),按順序求解子階段,前一子問題的解,為後一子問題的求解提供了有用的資訊。在求解任一子問題時,列出各種可能的區域性解,通過決策保留那些有可能達到最優的區域性解,丟棄其他區域性解。依次解決各子問題,最後一個子問題就是初始問題的解。
動態規劃中的子問題往往不是相互獨立的(即子問題重疊)。在求解的過程中,許多子問題的解被反覆地使用。為了避免重複計算,動態規劃演算法採用了填表來儲存子問題解的方法。


3、適用的情況

1)兩個必備要素

適合應用動態規劃方法求解的最優化問題應該具備兩個重要的要素:最優子結構和子問題重疊。

(a)最優子結構:問題的最優解由相關子問題的最優解組合而成,並且可以獨立求解子問題!

(b)子問題重疊:遞迴過程反覆的在求解相同的子問題。


2)三個性質

能採用動態規劃求解的問題的一般要具有3個性質:

(a) 最優化原理:如果問題的最優解所包含的子問題的解也是最優的,就稱該問題具有最優子結構,即滿足最優化原理。

(b) 無後效性:即某階段狀態(定義的新子問題)一旦確定,就不受這個狀態以後決策的影響。也就是說,某狀態以後的過程不會影響以前的狀態,只與其以前的狀態有關。

(c)有重疊子問題:即子問題之間是不獨立的(分治法是獨立的),一個子問題在下一階段決策中可能被多次使用到。(該性質並不是動態規劃適用的必要條件,但是如果沒有這條性質,動態規劃演算法同其他演算法相比就不具備優勢)

4、求解的基本步驟

實際應用中可以按以下幾個簡化的步驟進行設計:

    (1)分析最優解的性質,並刻畫其結構特徵,這一步的開始時一定要從子問題入手。

    (2)定義最優解變數,定義遞迴最優解公式。

    (3)以自底向上計算出最優值(或自頂向下的記憶化方式(即備忘錄法))

    (4)根據計算最優值時得到的資訊,構造問題的最優解

二,動態規劃的自我總結

實際上動態規劃的問題就是在犧牲一定量的記憶體儲存子問題的計算結果,從而未來需要這些資訊時不再重複計算,直接獲取計算過的結果即可。

其實動態規劃的問題不好想,除非遞推公式比較明顯。

1,動態規劃問題的判斷

那麼什麼樣的問題是動態規劃呢?

比如如下幾個經典問題

這一系列的問題都是最優值問題,能從題目中露骨的感受到求取最優結果的意思

比如最長迴文...最長上升序列...等等。實際上刷題刷多了之後一看就知道是動態規劃問題。

2,歸納設計步驟

實際應用中可以按以下幾個簡化的步驟進行設計:

    (1)定義子問題變數,分析遞迴最優解的公式。

              思考問題時一般都是將問題的規模縮小,即較小的子問題,假定其已經獲得了最優值,然後將其擴大一點點成為較大規模的子問題,那麼較大規模子問題應該怎樣從較小規模的子問題遞推公式得到呢?並且使得當前的子問題也是最優值。

    (2)分析最優解的性質,並刻畫其結構特徵。

                說白了就是刻意尋找定義的子問題變數與前面更小規模子問題變數的關係,一般用一個關係式表達。

    (3)以自底向上計算出最優值

               所謂自底向上的遞推過程,即由較小規模的子問題遍歷到原問題。首先我們的原問題是什麼?那麼他的較小規模的子問題是什麼?然後思考我們應該怎麼樣遍歷才能遍歷回原問題(首先思考遍歷的最外層)。在以後的遍歷過程就是通過某種遍歷順序遍歷回原問題。比如,最長迴文字串,我們定義的子問題就是“dp[i][j] 表示子串s[i…j]是否是迴文”。子串s[i…j]就是原問題的縮小版本,因為我們始終可以通過控制兩個變數變回原問題。

    (4)實際編寫程式時一定要記得初始化

          有的邊界問題可能不能由遞推公式獲得。比如最長迴文字串,必須先初始化,這一步一定要納入思考的範圍。


三,分析幾個經典的動態規劃例子

例子1

最長迴文字串

說真的這個動態規劃問題的子問題不好一下想到,為什麼不是“dp[i] 表示子串s[0…i]是否是迴文”呢?恐怕要經過多番假設子問題才能最終找到正確的子問題設定。

定義子問題:dp[i][j] 表示子串s[i…j]是否是迴文,我們這樣定義實際上變相知道了當前迴文子串的長度,以及在原字串中的位置。
1,初始化:
1),dp[i][i] = true (0 <= i <= n-1); 
2),if(s[i]==s[i+1]), dp[i][i+1] = true (0 <= i <= n-2); 
3),其餘的初始化為false

2,在初始化基礎上的遞推過程
如果子問題dp[i+1][j-1] == true,並且擴張一個位置後s[i] == s[j] 
顯然當前位置,dp[i][j] = true,否則還是為false(意義就是,小的子串都不是迴文,在此基礎上更大的子串也不是迴文)在動態規劃中更新最長迴文的長度及起點以及長度即可

3,自底向上的遍歷

從大的方向上來考慮:動態規劃是自底向上的遞推過程,即由較小規模的子問題遍歷到原問題。

首先我們的原問題是什麼?在給定字串s中尋找最長的迴文。

那麼他的較小規模的子問題是什麼?正如前面別人家的分析所知,我們必須先知道較短長度s.size()-2的子串是否是迴文,那麼s.size()的源字串就可以被判斷出來

接著嘮嗑,為了判斷“較短長度s.size()-1的子串是否為迴文”,我們必須先知道較短長度s.size()-3的子串是否是迴文,那麼s.size()-1的源字串就可以被判斷出來

接著嘮嗑,為了判斷“較短長度s.size()-2的子串是否為迴文”,我們必須先知道較短長度s.size()-4的子串是否是迴文,那麼s.size()-2的源字串就可以被判斷出來

...............

顯然迴圈的最外層就是當前要判斷的子串的長度,由小到大。

迴圈的最內層就是遍歷當前指定子串長度的起點和終點,

而最長的迴文在我們遍歷的過程更新即可!


例子2

跳臺階問題

定義子問題:令vec[i]表示跳到第i步可行的不同方式數目

接著尋找當前子問題vec[i]與前面子問題的關係,

如果是用兩步跳過來的(跳到第i步)則vec[i]=vec[i-2],因為這兩步已經確定了,那麼只有vec[i-2]中可能

如果是用一步跳過來的(跳到第i步)則vec[i]=vec[i-1],因為這一步已經確定了,那麼只有vec[i-1]中可能

時間複雜度:O(n)

空間複雜度:O(n)


例子3

經典的股票買賣問題

以下是123題的動態規劃分析(同樣適用於188題):

本體和揹包問題一樣,有兩個變數,第i天,交易第j次
定義子問題:f[i][j]表示前i天交易j次能得到的最大利潤 
1,

對於第i天的物品有兩種選擇情況:交易(買或者賣)或者不做任何交易
1)如果不做任何交易:
顯然,此時的最大利潤還是前一天的最大利潤f[j][i] =f[i-1][j] 
2)如果交易: 
為了能在這一天獲得最大利潤如果執行交易顯然只能賣股票(不能買),也就是說只能加上當前price[i]: 
那麼在加上此值price[i]之前的臨時利潤必須是最大的(可以反正法證明),我們稱之為最大臨時利潤maxtmp,

即如果交易,f[j][i] = prices[i] +maxtmp;

綜上兩種情況,f[j][i] = max(f[j][i-1], prices[i] +maxtmp);

繼續求取maxtmp,
對於最大臨時值maxtmp其實也是動態規劃過程
顯然遍歷陣列時求出最大,此時只有兩種情況:每一次可以買,也可以不買
a)若不買:顯然還是以前的maxtmp,即不變 
b)若買:為了能最大顯然是第j-1次的利潤減去,f[i][j - 1] - price[i]

綜上兩種情況,maxtmp=max(maxtmp,f[i][j - 1] - price[i])

更具體的分析為:
那麼假設第j次交易的買進股票是在第z天(實際上在那一天並不重要,我們只是要一個最大的臨時值maxtmp即可) ,其中0<z<i,,那麼必定有j-1次交易完成在z天以內,所以這一次交易的利潤就是price[i] - price[z]
那麼這種情況下的最大利潤f[i][j] 就是 f[z][j-1] + price[i]-price[z] 
那麼當我們遍歷到第i天,即在每次加上(遍歷到)price[i]這個已知值時,先求出price[i]之前的f[z][j-1]-price[z]這個臨時利潤值maxtmp (必須是最大的,其實就是模擬:用手頭已有的利潤減去買股票的支出,所剩的還是最大)


綜上所訴

f[j][i] = max(f[j][i-1], prices[i] +maxtmp);

maxtmp=max(maxtmp,f[i][j - 1] - price[i]);


例子4

楊輝三角問題

以下是118的分析,同樣適用於119.

定義子問題:result[i][j]為三角形i,j位置的值

1,初始化邊界:

for(int i=0;i<numRows;i++)//第一列 全為1
result[i][0]=1; 
for(int i=0;i<numRows;i++)//三角形對角線 全為1
result[i][i]=1; 

2,在初始化基礎上的遞推過程

比較顯然從第二行往下遞推:很容易看出result[i][j]=result[i-1][j]+result[i-1][j-1];


注:本博文為EbowTang原創,後續可能繼續更新本文。如果轉載,請務必複製本條資訊!

原文地址:http://blog.csdn.net/ebowtang/article/details/50791500

原作者部落格:http://blog.csdn.net/ebowtang

本部落格LeetCode題解索引:http://blog.csdn.net/ebowtang/article/details/50668895

相關推薦

LeetCode總結動態規劃問題小結

一,參考一般書籍中的“動態規劃”講解 1、基本概念 動態規劃(Dynamic Programming)對於子問題重疊的情況特別有效,因為它將子問題的解儲存在表格中,當需要某個子問題的解時,直接取值即

貪心演算法遞迴演算法動態規劃演算法比較與總結

一般實際生活中我們遇到的演算法分為四類: 一>判定性問題 二>最優化問題 三>構造性問題 四>計算性問題 而今天所要總結的演算法就是著重解決 最優化問題 《演算法之道》對三種演算法進行了歸納總結,如下表所示: 分

LeetCode—Minimum Path Sum 二維陣列最小路徑動態規劃

感覺這是一系列的動態規劃的演算法,正好也將動態規劃的演算法進行一個總結: 演算法一: 帶權重的最小路徑的問題 Given a m x n grid filled with non-negative numbers, find a path from top left to

LeetCode】120. Triangle 基於C++和Java的分析及解法動態規劃

120. Triangle Total Accepted: 69567Total Submissions: 229977Difficulty: Medium Given a triangle, find the minimum path sum from top t

【演算法】leetcode演算法筆記:二叉樹動態規劃和回溯法

前言 寫的比較匆忙,測試用例是能全部跑通的,不過考慮記憶體和效率的話,還有許多需要改進的地方,所以請多指教 在二叉樹中增加一行 題目描述 給定一個二叉樹,根節點為第1層,深度為 1。在其第 d 層追加一行值為 v 的節點。 新增規則:給定一個深度值 d (正整數),針對深度為 d-1 層的每一非

最大子矩陣最大連續子數組進階動態規劃初級poj1050

ostream 子數組 images 使用 運行時間 規劃 out 思考 turn 題目描述:現給出一個N*N矩陣,要求求出擁有最大和的子矩陣的和。 例如: 這樣的一個矩陣,最大子矩陣的和為15; 此題可以讓人聯想到求最大連續子數組,求最大子數組在上一篇文章中http:/

矩陣求連續遞減序列個數動態規劃初級遞歸poj1088

之一 urn end lan 問題 滑雪 sample 得出 再次 題目描述: Description Michael喜歡滑雪百這並不奇怪, 因為滑雪的確很刺激。可是為了獲得速度,滑的區域必須向下傾斜,而且當你滑到坡底,你不得不再次走上坡或者等待升降機來載你。Michael

【BZOJ2134】單位錯選(數學期望動態規劃

cto lin int 數學期望 long long www. () online code 【BZOJ2134】單位錯選(數學期望,動態規劃) 題面 BZOJ 題解 單獨考慮相鄰的兩道題目的概率就好了 沒了呀。。 #include<iostream> #inc

五大算法:分治貪心動態規劃回溯分支界定

適用於 return 子集 輸出 分治算法 適合 .com 回溯 難點 分治算法 一、基本概念 在計算機科學中,分治法是一種很重要的算法。字面上的解釋是“分而治之”,就是把一個復雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可

【BZOJ1023】仙人掌圖(仙人掌動態規劃

轉移 tps 同時 HR code main 最大值 mes vector 【BZOJ1023】仙人掌圖(仙人掌,動態規劃) 題面 BZOJ 求仙人掌的直徑(兩點之間最短路徑最大值) 題解 一開始看錯題了,以為是求仙人掌中的最長路徑。。。 後來發現看錯題了一下就改過來了。。

【CF613D】Kingdom and its Cities(虛樹動態規劃

-c www. AI gis IE long long als space gist 【CF613D】Kingdom and its Cities(虛樹,動態規劃) 題面 洛谷 CF 翻譯洛谷上有啦 題解 每次構建虛樹,首先特判無解,也就是關鍵點中存在父子關系。 考慮\(d

【BZOJ3162】獨釣寒江雪(樹哈希動態規劃

const pac string fine bool names 1=1 max 題解 【BZOJ3162】獨釣寒江雪(樹哈希,動態規劃) 題面 BZOJ 題解 忽然翻到這道題目,突然發現就是前幾天一道考試題目。。。 題解: 樹哈希,既然只考慮這一棵樹,那麽,如果兩個點為根

【算法導論】第15章動態規劃

ima 矩陣鏈乘 得到 方法 最優 一個 nbsp image com 動態規劃問題的步驟 1、描述最優解的結構 2、遞歸定義最優解的值 3、自底向上計算最優解的值 4、由計算的結果構造最優解 一般要在第3步記錄一些附加信息, 自底向上逐步計算還有另外一種方法,可以帶備

【BZOJ1047】[HAOI2007]理想的正方形(單調隊列動態規劃

geo cpp n) ace zoj != efi problem tchar 【BZOJ1047】[HAOI2007]理想的正方形(單調隊列,動態規劃) 題面 BZOJ 洛谷 題解 直接一個單調隊列維護一下沒給點和它前面的\(n\)個位置的最大值,再用一次單調隊列維護連續

【BZOJ1089】[SCOI2003]嚴格n元樹(高精度動態規劃

space mem www. ++ 只有一個 per ++i https 乘法 【BZOJ1089】[SCOI2003]嚴格n元樹(高精度,動態規劃) 題面 BZOJ 洛谷 題解 設\(f[i]\)表示深度為\(i\)的\(n\)元樹個數。然後我們每次加入一個根節點,然後枚

【BZOJ1898】[ZJOI2005]沼澤鱷魚(矩陣快速冪動態規劃

表示 ear 構建 esp ++ 方案 set 沒有 ring 【BZOJ1898】[ZJOI2005]沼澤鱷魚(矩陣快速冪,動態規劃) 題面 BZOJ 洛谷 題解 先吐槽,說好了的鱷魚呢,題面裏面全是食人魚 看到數據範圍一眼想到矩乘。 先不考慮食人魚的問題,直接設\(f[

【BZOJ1093】[ZJOI2007]最大半聯通子圖(Tarjan動態規劃

() queue 有一個 ble class empty cpp 之間 names 【BZOJ1093】[ZJOI2007]最大半聯通子圖(Tarjan,動態規劃) 題面 BZOJ 洛谷 洛谷的討論裏面有一個好看得多的題面 題解 顯然強連通分量對於題目是沒有任何影響的,直接

【BZOJ2246】[SDOI2011]迷宮探險(搜尋動態規劃

【BZOJ2246】[SDOI2011]迷宮探險(搜尋,動態規劃) 題面 BZOJ 洛谷 題解 乍一看似乎是可以求出每個東西是陷阱的概率,然而會發現前面走過的陷阱是不是陷阱實際上是會對當前狀態產生影響的。考慮一下狀壓,因為出了是陷阱和不是陷阱,還有一種情況是未知。所以三進位制狀壓。 \(0\)表示是有

洛谷P3953 逛公園(NOIP2017)(最短/長路拓撲排序動態規劃

洛谷題目傳送門 又是一年聯賽季。NOIP2017至此收官了。 這個其實是比較套路的圖論DP了,但是細節有點噁心。 先求出\(1\)到所有點的最短路\(d1\),和所有點到\(n\)的最短路\(dn\)。 設\(f_{i,j}\)表示\(i\)號點,所有與\(d1\)差距不超過\(j\)的路徑條數。轉移

【BZOJ5019】[SNOI2017]遺失的答案(FWT動態規劃

【BZOJ5019】[SNOI2017]遺失的答案(FWT,動態規劃) 題面 BZOJ 題解 發現\(10^8\)最多分解為不超過\(8\)個本質不同質數的乘積。 而\(gcd\)和\(lcm\)分別就是每個質因子的最大次冪和最小次冪的乘積。 那麼考慮一個狀壓\(dp\),設\(f[S1][S2]\)