小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
原题:64. 最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明: 每次只能向下或者向右移动一步。
如上图,路径 1→3→1→1→1 的总和最小,因此最后的结果是 7。
解题思路:
这是一个典型的动态规划题。因为每次只能向下或者向右移动一步,因此,从左上角开始,走到任何一个格子的做小路径和,都是「上方格子的最小路径和」与「左方格子的最小路径和」中较小的一个,加上当前格子本身的值。根据这个规律可以推导出状态转移方程:
定义一个与网格行列数相同的二维数组 dp[][],那么:
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
除了以上的一般情况,还有几种情况需要考虑:
- 当 i 和 j 都是 0 的时候,当前格子为左上角的个字,此时,
dp[i][j] = grid[i][j]。 - 当 i 是 0,j 大于 0 的时候,
dp[i][j] = dp[i][j-1] + grid[i][j]。 - 当 j 是 0,i 大于 0 的时候,
dp[i][j] = dp[i-1][j] + grid[i][j]。
从左上角到右下角依次按照以上的状态转移方程,dp 数组最右下角的元素既是结果。
另外,因为 dp 数组与题目参数 grid 数组大小相同,且过程中只需要左侧和上方格子的计算结果,因此可以直接在 grid 数组进行操作。
最终代码:
class Solution {
public int minPathSum(int[][] grid) {
int r = grid.length;
if (r == 0) {
return 0;
}
int c = grid[0].length;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (i == 0 && j == 0) {
continue;
} else if (i == 0) {
grid[i][j] += grid[i][j - 1];
} else if (j == 0) {
grid[i][j] += grid[i - 1][j];
} else {
grid[i][j] += Math.min(grid[i][j - 1], grid[i - 1][j]);
}
}
}
return grid[r - 1][c - 1];
}
}