给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明: 每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。此题是典型的动态规划问题,由于路径的方向只能是向下或向右,因此网格的第一行的每个元素只能从左上角元素开始向右移动到达,网格的第一列的每个元素只能从左上角元素开始向下移动到达,此时的路径是唯一的,因此每个元素对应的最小路径和即为对应的路径上的数字总和。对于不在第一行和第一列的元素,可以从其上方相邻元素向下移动一步到达,或者从其左方相邻元素向右移动一步到达,元素对应的最小路径和等于其上方相邻元素与其左方相邻元素两者对应的最小路径和中的最小值加上当前元素的值。
创建二维数组 dp,与原始网格的大小相同,dp[i][j] 表示从左上角出发到 (i, j) 位置的最小路径和。显然,dp[0][0]=grid[0][0]。对于 dp 中的其余元素,通过以下状态转移方程计算元素值。
最后得到 dp[m − 1][n − 1] 的值即为从网格左上角到网格右下角的最小路径和。
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] = grid[i][0] + dp[i - 1][0];
}
for (int j = 1; j < col; j++) {
dp[0][j] = grid[0][j] + dp[0][j - 1];
}
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[i][j] = grid[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[row - 1][col - 1];
}在我不会动态规划之前,其实第一次想到的会是递归处理,不过现在会了,还是动态规划香哈哈哈,在这里我仅仅说一下递归解题思路。
我们从 [0, 0] 坐标出发,最短路径是 f[0][0] + min(f[0][1], f[1][0]) ,针对 f[0][1] 和 f[1][0] 继续进行递归处理。这里需要注意的一点是,我们在计算 f0 和 f[1][0] 的时候,会重复计算 f[0][1],所以我们使用一个 min[i][j] 数组保存 [i, j] 坐标到右下角的最小路径,这样就避免的重复计算。