leetcode 64. 最小路徑和 -- javascript DP

題目描述:

給定一個包含非負整數的 m x n 網格 grid ,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和爲最小。算法

說明: 每次只能向下或者向右移動一步。markdown

image.png

題解:

動態規劃(Dynamic Programming, DP)

  • 動態規劃只能應用於有最優 子結構的問題。最優子結構的意思是局部最優解能決定全局最優解(對有些問題這個要求並不能徹底知足,故有時須要引入必定的近似)。spa

  • 簡單地說,問題可以分解成子問題來解決code

  • 通俗一點來說,動態規劃和其它遍歷算法(如深/廣度優先搜索)都是將原問題拆成多個子問題而後求解,他們之間最本質的區別是,動態規劃保存子問題的解,避免重複計算orm

  • 解決動態規劃問題的關鍵是找到狀態轉移方程,這樣咱們能夠通計算和儲存子問題的解來求解最終問題it

  • 同時,咱們也能夠對動態規劃進行空間壓縮,起到節省空間消耗的效果。io

  • 在一些狀況下,動態規劃能夠當作是帶有狀態記錄(memoization)的優先搜索table

  • 動態規劃是自下而上的,即先解決子問題,再解決父問題;function

  • 而用帶有狀態記錄的優先搜索自上而下的,即從父問題搜索到子問題,若重複搜索到同一個子問題則進行狀態記錄,防止重複計算。class

  • 若是題目需求的是最終狀態,那麼使用動態搜索比較方便;

  • 若是題目須要輸出全部的路徑,那麼使用帶有狀態記錄的優先搜索會比較方便。

回到本題目

dp[i][j] 表示從左上角開始到 (i, j) 位置的最

優路徑的數字和。由於每次只能向下或者向右移動,咱們能夠很容易獲得狀態轉移方程 dp[i][j] =

min(dp[i-1][j], dp[i][j-1]) + grid[i][j]

var minPathSum = function(grid) {
   let m = grid.length, n = grid[0].length;
   let dp = Array.from({length: m}, ()=> new Array(n).fill(0));
   for(let i = 0; i < m; i++) {
       dp[i][0] = i === 0 ? grid[i][0] : dp[i-1][0] + grid[i][0];
   }
   for(let j = 0; j < n; j++) {
       dp[0][j] = j === 0 ? grid[0][j] : dp[0][j - 1] + grid[0][j];
   }
   for(let i = 1; i < m; i++){
      for(let j = 1; j < n; j ++) {
          dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
      }
   }
   return dp[m-1][n-1];
};
複製代碼

壓縮空間

var minPathSum = function(grid) {
   let m = grid.length, n = grid[0].length;
   let dp = new Array(n).fill(0);
   for(let i = 0; i < m; i++){
      for(let j = 0; j < n; j ++) {
          if(i== 0 && j== 0) {
              dp[j] = grid[i][j]
          }else if(i == 0) {
              dp[j] = dp[j-1] + grid[i][j]
          }else if(j === 0) {
              dp[j] = dp[j] + grid[i][j]
          }else{
              dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j]; 
          }
           
      }
   }
   return dp[n-1];
};
複製代碼
相關文章
相關標籤/搜索