「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」。
题目:给定一个m*n的网格,每个网格都对应一个非负整数,现要求找出一条从起点到终点的路径(其中起点为00点,终点为网格最后一个点),使得该路径上的数之和最小。
解题思路
本题是经典的动态规划问题,通过不断更新状态转移矩阵即可得到最终的解,动态规划的题目含有一个套路,首先确定该问题可以由一个个小问题解决,之和找到状态之间的转移关系,初始化状态转移数组,之后进行状态的确定即可。
我们首先分析本题,假设选定的示例为下面这个:
| 1 | 3 | 1 |
|---|---|---|
| 1 | 5 | 1 |
| 4 | 2 | 1 |
对于第一个1,此时我们有两个方向可以走,分别是向下和向右,那么究竟是哪个呢?可能有人说是向下,因为下面的1小,实则不然,如果向下,那在下一步就是4或5,显然最终和明显增大。
我们可以对上面矩阵进行分解,1本身就是1,那么如果向右,则就是下列矩阵从3开始到1的路径最小和。
| 3 | 1 |
|---|---|
| 5 | 1 |
| 2 | 1 |
如果向下,则是下列矩阵从1开始到1的最小路径之和。
| 1 | 5 | 1 |
|---|---|---|
| 4 | 2 | 1 |
以此类推,我们可以发现可以将本问题一步步简单化,最终必然可以得到最终结果。
通过上面的过程,我们可以发现我们将问题一步步拆解,大问题变成了一个个小问题,我们只需要将这些小问题的答案进行组合即可,那么此时就需要一个容器来保存小问题的结果,这个容器就是动态规划的状态转移矩阵,该矩阵大小和网格大小相同,而对于上边界和左边界元素,都可以利用已知元素直接初始化,而对于中间的元素,其值取决于该元素的左边和上边的值,其状态转移方程为:,代码如下:
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
int row = grid.length, column = grid[0].length;
int[][] dp = new int[row][column];
dp[0][0]=grid[0][0];
for(int i=1;i<row;i++){
dp[i][0] = dp[i-1][0] + grid[i][0];
}
for(int i=1;i<column;i++){
dp[0][i] = dp[0][i-1] + grid[0][i];
}
for(int i=1;i<column;i++){
for(int j=1;j<row;j++){
dp[j][i] = grid[j][i] + Math.min(dp[j-1][i], dp[j][i-1]);
}
}
return dp[row-1][column-1];
}
上述代码时间复杂度为, 空间复杂度也为。最终耗时2ms。