動態(tài)規(guī)劃算法的兩種經(jīng)典解決方式:最優(yōu)子結(jié)構(gòu)和DP數(shù)組的使用解析

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

動態(tài)規(guī)劃算法問題

  • 什么叫作最優(yōu)子結(jié)構(gòu)? 和動態(tài)規(guī)劃有什么關(guān)系?
  • 為什么動態(tài)規(guī)劃遍歷DP數(shù)組的方式有正著遍歷,有倒著遍歷,有斜著遍歷?

最優(yōu)子結(jié)構(gòu)

  • 最優(yōu)子結(jié)構(gòu)是某些問題的一種特定的性質(zhì),并不是動態(tài)規(guī)劃問題所特有的.
  • 很多問題都具有最優(yōu)子結(jié)構(gòu),但是其中大部分不具有重疊子問題,所以不會歸為動態(tài)規(guī)劃系列的問題
  • 最優(yōu)子結(jié)構(gòu):
    • 可以從子問題的最優(yōu)結(jié)果推導(dǎo)出更大規(guī)模問題的最優(yōu)結(jié)果
    • 子問題之間必須相互獨立
  • 通過改造問題來優(yōu)化由于子問題之間不獨立而導(dǎo)致的最優(yōu)子結(jié)構(gòu)失效的情況:
    • 問題: 假設(shè)學(xué)校有10個班,已知每個班的最高分與最低分差值的最大分?jǐn)?shù)差,需要計算全校學(xué)生中的最大分?jǐn)?shù)差
    • 分析: 這樣的問題就無法通過這10個班的最大分?jǐn)?shù)差來推導(dǎo)出來,因為這10個班的最大分?jǐn)?shù)差不一定就包含全校學(xué)生的最大分?jǐn)?shù)差.比如全校的最大分?jǐn)?shù)差可能是由8班的最高分和6班的最低分的分?jǐn)?shù)差而得.這樣就導(dǎo)致子問題之間不是互相獨立的
    • 改造問題: 直接進行問題改造
    int result = 0;
    for (Student a : school) {
      for (Student b : school) {
          if (a is b) {
              continue;
          } 
          result = max(result, |a.score - b.score|)
      }
    }
    return result;
    
  • 改造問題就是將問題等價轉(zhuǎn)化:
    • 最大分?jǐn)?shù)差就等價于最高分?jǐn)?shù)與最低分?jǐn)?shù)的差
    • 那么就是要求最高和最低分?jǐn)?shù)
    • 求最高分?jǐn)?shù)是具備最優(yōu)子結(jié)構(gòu)的,求最低分?jǐn)?shù)也是具有最優(yōu)子結(jié)構(gòu)的
    • 這樣就樣一個不具備最優(yōu)子結(jié)構(gòu)的問題轉(zhuǎn)化為具備最優(yōu)子結(jié)構(gòu)的子問題
    • 借助最優(yōu)子結(jié)構(gòu)解決最值問題,再解決最大分?jǐn)?shù)差問題
  • 題目: 求一棵二叉樹的最大值,假設(shè)節(jié)點中的值都為非負數(shù)
int maxVal(TreeNode root) {
    if (root == null) {
        return -1;
    }
    int left = maxVal(root.left);
    int right = maxVal(root.right);
    return max(root.val, left, right);
}

這個問題符合最優(yōu)子結(jié)構(gòu),以root為根的樹的最大值可以通過兩邊子樹的子問題的最大值推導(dǎo)出來

最優(yōu)子結(jié)構(gòu)總結(jié)

  • 最優(yōu)子結(jié)構(gòu)并不是動態(tài)規(guī)劃獨有的一種性質(zhì),但是能求最值的問題大部分都會具備最優(yōu)子結(jié)構(gòu)的性質(zhì)
  • 最優(yōu)子結(jié)構(gòu)性質(zhì)作為動態(tài)規(guī)劃問題的必要條件,一定是可以用來求最值的: 通常情況下,最值的問題,思路往動態(tài)規(guī)劃想就對了
  • 動態(tài)規(guī)劃就是從最簡單的base case往后推導(dǎo), 類似一種鏈?zhǔn)椒磻?yīng).但是只有具備最優(yōu)子結(jié)構(gòu)的問題,才會有發(fā)生這種鏈?zhǔn)椒磻?yīng)的性質(zhì)
  • 最優(yōu)子結(jié)構(gòu)的尋找過程:
    • 就是證明狀態(tài)轉(zhuǎn)移方程正確性的過程
    • 方程符合最優(yōu)子結(jié)構(gòu)就可以直接遞歸求解
    • 寫出直接遞歸求解后可以根據(jù)遞歸樹看出有沒有重疊子問題,如果有則進行優(yōu)化

DP數(shù)組的遍歷方向

  • 動態(tài)規(guī)劃中DP數(shù)組遍歷順序問題:
    • 示例: 二維DP數(shù)組
      • 正向遍歷:
      int[][] dp = new int[m][n];
      for (int i = 0; i < m; i++) {
          for (int j = 0; j < n; j++) {
              /*
               * 計算dp[i][j]
               */  
               ...
          }   
      }   
      
      • 反向遍歷:
      int[][] dp = new int[m][n];
      for (int i = m-1; i >= 0; i--) {
          for (int j = n - 1; j >= 0; j--) {
              /*
               * 計算dp[i][j]
               */
               ...
          }
      }
      
      • 斜向遍歷:
      int[][] dp = new int[m][n];
      for (int l = 2; l <= n; l++) {
          for (int i = 0; i <= n - l; i++) {
              int j = l + i - 1;
              /*
               * 計算dp[i][j]
               */
          }
      }
      
  • DP數(shù)組的遍歷的兩條原則:
    • 遍歷的過程中,所需的狀態(tài)必須是已經(jīng)計算出來的
    • 遍歷的終點必須是存儲結(jié)果的位置

編輯距離問題

  • 通過對DP數(shù)組的定義,確定了:
    • base case : dp[n][0]dp[0][n]
    • 最終答案 : dp[m][n]
  • 通過狀態(tài)轉(zhuǎn)移方程知道:
    • dp[i][j] 需要從dp[i-1][j], dp[i][j-1], dp[i-1][j-1] 轉(zhuǎn)移而來
  • 再根據(jù)DP數(shù)組遍歷的兩條原則,確定使用正向遍歷:
for (int i = 1; i < m; i++) {
    for (int j = 1; j < n; j++) {
        /*
         * 通過dp[i-1][j], dp[i][j-1], dp[i-1][j-1]計算dp[i][j]
         */
    }
}
  • 這樣每一步迭代的左邊,上邊,左上邊的位置都是base case或者之前計算出來的值
  • 最終結(jié)束在結(jié)果的位置dp[m][n]

回文子序列

  • 通過對DP數(shù)組的定義,確定了:
    • base case處在中間的對角線
    • 最終答案: dp[0][n-1]
  • 通過狀態(tài)轉(zhuǎn)移方程知道:
    • dp[i][j] 需要從dp[i+1][j], dp[i][j-1], dp[i+1][j-1] 轉(zhuǎn)移而來
  • 再根據(jù)DP數(shù)組遍歷的兩條原則,確定有兩種遍歷方式:
    • 從左至右斜著遍歷
    • 從下向上從左到右遍歷
  • 這樣每一步迭代的左邊,下邊,左下邊已經(jīng)計算出來值
  • 最終結(jié)束在結(jié)果的位置 dp[0][n-1]

DP數(shù)組遍歷總結(jié)

  • DP數(shù)組遍歷主要就是看base case最終結(jié)果的存儲位置類決定遍歷順序
  • 選擇的遍歷順序要保證遍歷過程中使用的數(shù)據(jù)都是計算完畢的
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容