[LeetCode] 64. 最小路径和 ☆☆☆(动态规划)

描述

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

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

示例:

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

解析

由于我们的目的是从左上角到右下角,最小路径和是多少,那我们就定义 dp[i] [j]的含义为:当从左上角走到(i, j) 这个位置时,最下的路径和是 dp[i] [j]。那么,dp[m-1] [n-1] 就是我们要的答案了。

想象以下,要怎么样才能到达 (i, j) 这个位置?由于可以向下走或者向右走,所以有两种方式到达

一种是从 (i-1, j) 这个位置走一步到达

一种是从(i, j - 1) 这个位置走一步到达

不过这次不是计算所有可能路径,而是计算哪一个路径和是最小的,那么我们要从这两种方式中,选择一种,使得dp[i] [j] 的值是最小的,显然有

dp[i] [j] = min(dp[i-1][j],dp[i][j-1]) + arr[i][j];// arr[i][j] 表示网格中的值

初始值:

当 dp[i] [j] 中,如果 i 或者 j 有一个是 0,那么还能使用关系式吗?答是不能的。

因为这个时候把 i - 1 或者 j - 1,就变成负数了,数组就会出问题了,所以我们的初始值是计算出所有的 dp[0] [0….n-1] 和所有的 dp[0….m-1] [0]。这个还是非常容易计算的,相当于图中的最上面一行和左边一列。因此初始值如下:

dp[0] [j] = arr[0] [j] + dp[0] [j - 1]; // 相当于第一行,只能一直往左走

dp[i] [0] = arr[i] [0] + dp[i - 1] [0]; // 相当于第一列,只能一直往下走

代码

public int minPathSum(int[][] grid) {
        if (null == grid || grid.length <= 0) {
            return 0;
        }
        int[][] dp = new int[grid.length][grid[0].length];
        dp[0][0] = grid[0][0];
        for (int i = 1; i < dp.length; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int i = 1; i < dp[0].length; i++) {
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }
        for (int ii = 1; ii < dp.length; ii++) {
            for (int kk = 1; kk < dp[0].length; kk++) {
                dp[ii][kk] = Math.min(dp[ii - 1][kk], dp[ii][kk - 1]) + grid[ii][kk];
            }
        }
        return dp[grid.length - 1][grid[0].length - 1];
    }
原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/11857564.html