動態規劃套路

到底怎麼學動態規劃?

回想起當初學動態規劃的時候,是真的難。動態規劃的確很難,很考驗邏輯思惟能力、抽象能力、還有數學建模能力。 可是入門動態規劃真的有這麼難嗎?我覺的其實真的不難,就是單純的找規律;這裏我想以一種比較野路子的方式幫助你們入門理解動態規劃,這種方法真的是很簡單且有效果,大神請忽略。markdown

DP table

什麼方法呢?直接畫表格,找規律。 這個辦法在不少題目下都是很是的有效果,特別是矩陣型dp,簡直是萬金油;這種方法很是簡單,你只須要記住兩個技巧。spa

  1. 把問題的規模變小,變成小問題思考
  2. 根據小問題來填表格,找出規律

記住這兩個技巧,下面我以一道相對簡單,一道稍微難一點的真題還講解。code

62.不一樣路徑

首先分析一下題目,題目說機器人只能往下,或者往右走,到達右下角有多少種走法。

  • 不要單純的幹想,單純的幹想會浪費不少的時間,甚至手足無措,徹底不知道怎麼辦了,直接畫表格找規律,這裏我以一個5*7的表格來舉例。

  • 首先爲何第一行第一列全是1?由於若是隻有第一行第一列,機器人就只有一條路可走。
  • 回憶一下上面兩個技巧;假設咱們把網格變小,也就是把問題的規模變小,變成一個3*3的表格。
  • 3*3 有多少種走法很簡單吧?直接把表格填完就能夠獲得答案了,答案就是6種。
  • 爲何是6種呢?由於機器人只能往右或者往下走,到達3 * 3的最右下角,只能往上面下來,或者左邊過來。
  • 那若是把問題的規模繼續變大,變成4*4的表格呢?咱們繼續填表

  • 繼續觀察答案,答案是20種;那有什麼規律呢?我相信沒有人會發現不了這個規律吧?
  • 很明顯,table[3][3] = table[2][3] + table[3][2],也就是說機器人走到規模爲4 * 4的網格右下角有20種走法。

書寫代碼

到這裏,我相信寫出代碼應該不難了吧?orm

var uniquePaths = function (m, n) {
  // 由於第一行第一列都是1
  let dp = Array.from(new Array(m), () => new Array(n).fill(1))
  for(let i = 1; i < m; i++){
    for(let j = 1; j < n; j++){
      // 當前的等於上面的(dp[i - 1][j])+ 左邊的(dp[i][j - 1])
      dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
    } 
  }
  return dp[m - 1][n - 1]
};
複製代碼

其實動態規劃也就這麼簡單,就是單純的畫表格找規律。數學

1143.最長公共子序列

  • 分析下題目,要找兩個串的最長公共子序列,不要多想。直接畫表格觀察規律

  1. 爲何會有空串?爲何空串對應的都是0?你想呀,須要從無到有推導出答案,找出規律,因此須要藉助空串;若是兩個串中的其中一個爲空,那確定都是0呀。
  2. 由於用例的答案是3,全部我先把結果先上去,好利用這個結果來找出規律。
  3. 咱們繼續填表推導,找出規律。

  • 當問題的規模變大,text1[0] == text2[0],答案很明顯是1。這裏咱們就發現了相等的時候要加1了,好傢伙,繼續觀察。

  • 爲何我會先填 text1[0] == text2[0] 對應的行和列呢?由於當text1/text2的長度繼續變長的時候,最終的結果會受影響嗎?很明顯,不受影響,繼續填表找規律。

  • 當咱們填到text1[i] == text2[j],也就是c字符相等的時候,由以前找到的規律,它必定要加1,可是在哪一個基礎上加1呢?很明顯是問題的規模變小的時候,也就是沒有c這個字符的時候,也就是表格的table[1][2],綠色區域爲1的塊。
  • 繼續以這個規律填表格看看,咱們看紅色塊。

  • 最終驗證了答案,當兩個字符相等的時候,就等於上一個規模小的問題加1,不想等的就至關於有沒有這個字符都同樣。取兩個串少一個的狀況下的最大值就能夠了。
  • 因此規律以下:
  1. text1[i] == text2[j], table[i][j] = table[i - 1][j - 1] + 1
  2. text1[i] != text2[j], table[i][j] = max(table[i - 1][j], table[i][j - 1])

書寫代碼

var longestCommonSubsequence = function(text1, text2) {
  let n = text1.length
  let m = text2.length
  let dp = Array.from(Array(n + 1), () => Array(m + 1).fill(0))
  //空串都是0,0不用看了 
  for(let i = 1; i <= n; i++){
    for(let j = 1; j <= m; j++){
      if(text2[j - 1] == text1[i - 1]){
         dp[i][j] = dp[i - 1][j - 1] + 1
      }else{
         dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
      }
    }
  }
  return dp[n][m]
};
複製代碼

總結

其實這種辦法寫動態規劃是很是野路子的,可是對於新手來講,入門確實不錯。 動態規劃確實有點難,把它講明白,講清楚也不簡單,但願我這篇水文能幫助你更好的理解動態規劃吧。互聯網人共勉~it

相關文章
相關標籤/搜索