給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。
**說明:**每次只能向下或者向右移動一步。
示例:
輸入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
輸出: 7
解釋: 因為路徑 1→3→1→1→1 的總和最小。
複製程式碼
昨天做了道演算法題,感覺畫圖很有助於自己理解演算法的過程,這次再挑一個演算法加深印象。碰到這種型別的題目,和遞迴很像,但是使用遞迴,如果資料範圍比較大,就會花費很長時間。
動態規劃(英語:Dynamic programming,簡稱DP)是一種在數學、管理科學、電腦科學、經濟學和生物資訊學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。 動態規劃常常適用於有重疊子問題和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於樸素解法。
廢話少說
解題
根據題意,到達網格中的某個點最短,可以理解為網格中的任何一個點都是可以走過去的,而且任何一個網格都有一個最短的路徑。
那麼我們使用一種資料結構儲存,從頂點到達網格中任意一點的最短位置。根據人的正常邏輯,畫圖如下:
- 從頂點按照行來遍歷每一個位置,計算每一個位置的最小路徑
根據上面的圖片可以瞭解:
- 當
點
處於第一行的時候,它的最短路徑就是同一行的前一個位置加上當前位置 - 當
點
處於第一列的時候,它的最短路徑就是上一行的位置加上當前位置 - 當
點
處於頂點的時候,它就是頂點的值 - 當
點
位於中間的位置,它是其上一行或上一列的最小值加上當前的值
至此,我們寫程式如下:
public static int minPathSumAi(int[][] grid){
// 特殊情況處理
if (grid.length == 0){
return 0;
}
// 新建一個標記陣列,標記到每個位置的最短路徑
int xLen = grid.length;
int yLen = grid[0].length;
int[][] markBit = new int[xLen][yLen];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
// 初始位置
if (i == 0 && j == 0){
markBit[i][j] = grid[i][j];
}
// 當點在第一行的位置時
else if (i == 0){
markBit[i][j] = markBit[i][j-1] + grid[i][j];
}
// 當點在第一列的位置時
else if (j == 0){
markBit[i][j] = markBit[i-1][j] + grid[i][j];
}
// 當點在陣列的中間位置時
else {
markBit[i][j] = Math.min(markBit[i-1][j] , markBit[i][j-1]) + grid[i][j];
}
}
}
return markBit[xLen-1][yLen-1];
}
複製程式碼
然後到LeetCode上測試,效能有待於提升,後續水平提高之後再想更優的方案吧,目前先理解解題方式。
最後
程式的執行都是人控制的,在程式執行之前,確保你自己的邏輯清晰,畫圖可以幫你理清邏輯。