手摸手提桶跑路——LeetCode64. 最小路径和

1,021 阅读2分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情

题目描述

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明: 每次只能向下或者向右移动一步。

示例 1:

捕获.PNG

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

示例 2:

输入: grid = [[1,2,3],[4,5,6]]
输出: 12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 100

解题思路——DP

这道题可以使用动态规划来解。

我们设 dp 为大小 m * n 矩阵,其中 dp[i][j] 的值代表走到 (i, j) 的最小路径和。

我们从图一示例图中观察到,如果只能向右和向下走的话,那么第一行除了第一个格子外,其他的格子只能是从左边过来的,同理,第一列中除了第一个格子外,其他的格子只能是从上面过来的。那么我们就可以得到初始状态:

  • 对于第一行来说:grid[i][j] = grid[i][j - 1] + grid[i][j]
  • 对于第一列来说:grid[i][j] = grid[i - 1][j] + grid[i][j]

除此之外,题目规定,其他的格子只能从上一个格子或者左边的格子到达。那么要求得最小的路径,我们需要这两个格子的路径和中最小的那个,即 Math.min(左边格子的路径和,上面格子的路径和) + 当前格子 grid[i][j] ,因此可以列出动态转移方程:

  • 动态转移方程:grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];

最后返回 dp 数组中的最后一个元素的值。

需要注意的是,这道题可以直接在 grid 数组上做文章,不需要建立额外的 dp 数组,因为 grid[i][j] 计算完毕后,就不需要保存原数据了,其他依赖 grid[i][j] 的格子,需要的只是 最小路径和

题解

/**
 * @param {number[][]} grid
 * @return {number}
 */
var minPathSum = function(grid) {
    const m = grid.length, n = grid[0].length;

    for(let i=0; i<m; ++i) {
        for(let j=0; j<n; ++j) {
            if(i === 0 && j === 0) continue;
            else if(i === 0) {
                grid[i][j] = grid[i][j - 1] + grid[i][j];
            } else if(j === 0) {
                grid[i][j] = grid[i - 1][j] + grid[i][j];
            } else {
                grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];
            }
        }
    }

    return grid[m - 1][n - 1];
};

捕获.PNG