1.题目链接:
2.题目描述:给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
3. 解法(动态规划):
算法思路:
像这种表格形式的动态规划,是非常容易得到「状态表示」以及「状态转移方程」的,可以归结到「不同路径」一类的题里面。
1. 状态表示:
对于这种路径类的问题,我们的状态表示一般有两种形式:
i. | 从 [i, j] 位置出发,巴拉巴拉; |
ii. 从起始位置出发,到达 [i, j] 位置,巴拉巴拉。这里选择第二种定义状态表示的方式:
dp[i][j] 表示:到达 [i, j] 位置处,最小路径和是多少。
2. 状态转移:
简单分析一下。如果 dp[i][j] 表示到达 到达 [i, j] 位置处的最小路径和,那么到达 [i, j] 位置之前的一小步,有两种情况:
i. | 从 [i - 1, j] 向下走一步,转移到 [i, j] 位置; |
ii. 从 [i, j - 1] 向右走一步,转移到 [i, j] 位置。
由于到 [i, j] 位置两种情况,并且我们要找的是最小路径,因此只需要这两种情况下的最小值,再加上[i, j] 位置上本身的值即可。
也就是:dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
3. 初始化:
可以在最前面加上一个「辅助结点」,帮助我们初始化。使用这种技巧要注意两个点:i. 辅助结点里面的值要「保证后续填表是正确的」;
ii. 「下标的映射关系」。
在本题中,「添加一行」,并且「添加一列」后,所有位置的值可以初始化为无穷大,然后让 dp[0][1] = dp[1][0] = 1 即可。
4. 填表顺序:
根据「状态转移方程」的推导来看,填表的顺序就是「从上往下」填每一行,每一行「从左往后」。
5. 返回值:
根据「状态表示」,我们要返回的结果是 dp[m][n] 。
Java算法代码:
class Solution {
public int minPathSum(int[][] grid) {
// 1.创建dp表
// 2.初始化
// 3.填表
// 4.返回值
int m = grid.length, n = grid[0].length;
int[][] dp = new int[m+1][n+1];
for(int j = 0; j <= n; j++) dp[0][j] = 0x3f3f3f;
for(int i = 0; i <= m; i++) dp[i][0] = 0x3f3f3f;
dp[0][1] = dp[1][0] = 0;
for(int i = 1; i <= m; i++){
for(int j =1; j <= n; j++){
dp[i][j] = Math.min(dp[i - 1][j],dp[i][j-1]) + grid[i-1][j-1];
}
}
return dp[m][n];
}
}
运行结果:
动态规划: