動態規劃之最短路徑和

Real_man發表於2019-03-20

給定一個包含非負整數的 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上測試,效能有待於提升,後續水平提高之後再想更優的方案吧,目前先理解解題方式。

image-20190320161740838

最後

程式的執行都是人控制的,在程式執行之前,確保你自己的邏輯清晰,畫圖可以幫你理清邏輯。

參考

相關文章