秋招-算法-最短路径和

276 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>\

一、题目描述

给定一个 m*n 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上左右数字累加起来就是路径和,输出所有的路径中最小的路径和。
数据范围:1<=n,m<=500,矩阵中任意值都满足 0<= nums <= 100
要求:时间复杂度O(nm)

输入: grid = [[1,3,1],[1,5,1],[4,2,1]]
输出: 7
解释: 因为路径 13111 的总和最小。

二、思路分析

1.本题为经典的二维动态规划题目。
2.使用动态规划思想时,考虑如何将问题进行合理拆分,使其变为由一个一个子问题组,通过求解子问题从而解决最后的问题。本题需要求解从左上走到右下(grid[0][0]→grid[n-1][m-1])所需的最小路径和,可以考虑走到grid[n-1][m-2]和grid[n-2][m-1]时哪个路径最短,以此类推。。。
3.在划分子问题时可以分为三种情况:
(1)网格的第一行的每个元素只能从左上角元素开始向右移动到达
(2)网格的第一列的每个元素只能从左上角元素开始向下移动到达
(3)对于不在第一行和第一列的元素,可以从其上方相邻元素向下移动一步到达,或者从其左方相邻元素向右移动一步到达
所以状态转移方程也分为3个:
(1)dp[0][i] = dp[0][i-1] + grid[0][i]
(2)dp[j][0] = dp[j-1][0] + grid[j][0]
(3)dp[i][j] = Math.min(dp[i-1][j] + grid[i][j], dp[i][j-1] + grid[i][j])

三、代码

class App{
    public int minPathSum(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0){
            return 0;
        }
        int row = grid.length;
        int col = grid[0].length;
        int[][] dp = new int[row][col];
        dp[0][0] = grid[0][0];
        for (int i=1; i<row; i++){
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }
        for (int j=1; j<col; j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        for (int i=1; i<row; i++){
            for (int j=0; j<col; j++){
                dp[i][j] = Math.min(dp[i-1][j] + grid[i][j], dp[i][j-1] + grid[i][j]);
            }
        }
        return dp[row-1][col-1];
    }
}

四、总结

本题使用动态规划思想,建立二维动态规划数组,将每走到一个格子的最短路径值存储到数组的相应位置,最后只需得到数组右下角格子的值就可以得到问题的最终解。其时间复杂度为O(nm),空间复杂度为O(nm)。