題目:給定一個矩陣,從左上角開始每次只能向右或者向下移動,最後到達右下角的位置,路徑上的全部的數字累加起來做爲這條路徑的路勁和。要求返回全部路徑和中的最小路徑和。數組
舉例:blog
路徑1,3,1,0,6,1,0是全部路徑中路徑和最小的,因此返回其和12。io
解析:class
這個題目很相似以前的那個動態規劃的數字三角的問題。毫無疑問的,這個問題也是用動態規劃解決。只要肯定了狀態和轉移方程,這個題目很容易解決。下面直接給出代碼:方法
//利用path記錄路徑,對於每個path[i][j],0表明dp[i][j]的值從上面加過來,1表明dp[i][j]的值從左邊加過來 int minPathSum1(int matrix[][col], int dp[][col], int path[][col]) { if(matrix == NULL) { return 0; } dp[0][0] = matrix[0][0]; //計算第一列的值 for(int i = 1; i < row; i ++) { dp[i][0] = dp[i - 1][0] + matrix[i][0]; path[i][0] = 0; } //計算第一行的值 for(int j = 1; j < col; j++) { dp[0][j] = dp[0][j- 1] + matrix[0][j]; path[0][j] = 1; } //計算其它的值 for(int i = 1; i < row; i++) { for(int j = 1; j < col; j++) { int direction = dp[i][j-1] < dp[i-1][j] ? 1 : 0; dp[i][j] = (direction ? dp[i][j-1] : dp[i-1][j]) + matrix[i][j]; path[i][j] = direction; } }//for return dp[row - 1][col - 1]; }
這裏在dp上存儲每一個點的最短路徑和,在path上存儲這個最短路徑是哪一個點過來的。這樣就能在找到最短路徑和的同時,把路徑一塊找到。im
上面的題目很簡單,不是這篇文章的重點,下面來看一下二維動態規劃的空間壓縮問題。上面的動態規劃的時間複雜度是O(M*N),空間複雜度就是二維數組的大小O(M*N)。空間壓縮的方法是不用記錄全部的子問題的解。因此就能夠只用一個行數組記錄第一行、第二行...一次計算。直到最後一行,獲得dp[N-1]就是左上角到右下角的最小路徑和。二維數組
代碼實現:db
int minPathSum2(int matrix[][col], int dp[]) { dp[0] = matrix[0][0]; //計算第一行的最短路徑 for(int j = 1; j < col; j++) { dp[j] = dp[j-1] + matrix[0][j]; } //計算除了第一行的其它最小路徑和 for(int i = 1; i < row; i++) { for(int j = 0; j < col; j++) { if(j == 0) { dp[j] += matrix[i][j]; } else { dp[j] = dp[j-1] < dp[j] ? dp[j-1] : dp[j]; dp[j] += matrix[i][j]; } }//for }//for return dp[col - 1]; }
這種二維動態規劃的空間壓縮幾乎能夠應用到全部的二維動態規劃的題目中,經過一個數組(列數組或者航數組)滾動更新的方式節省了大量的空間。可是在滾動的過程當中動態規劃表不斷的被行數組或者列數組覆蓋更新,最後獲得的僅僅是動態規劃表的最後一行或者最後一列的最小路徑和。因此真正的最小路徑是不能經過動態規劃表回溯獲得的。img