题目描述
给定一个包含非负整数的 m * n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
每次只能向下或向右移动一步。
思路
参考自:https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/
动态规划
- 状态定义:
- 设 dp 为 m * n 矩阵,其中 dp[i][j] 的值代表直到走到 (i, j) 的最小路径和。
- 转移方程:
i 是行(m = grid.length),j是列(n = grid[0].length)
当前单元格(i, j)只能从左方单元格(i, j - 1) 与上方单元格(i - 1, j)走到因此只需要考虑矩阵左边界和右边界。- 走到当前单元格(i, j)的最小路径和 = “从左方单元格(i, j - 1) 与上方单元格(i - 1, j)走来的 两个最小路径和中较小的” + 当前单元格值 grid[i][j]。具体分为以下 4 种情况:
- 当左边和上边都不是矩阵边界时: 即 i != 0,j != 0 时,dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
- 当只有左边是矩阵边界时: 只能从上面来,即当 i != 0,j = 0时,dp[i][j] = dp[i - 1][j] + grid[i][j];
- 当只有上边是矩阵边界时: 只能从左边来,即当 i = 0, j! = 0时,dp[i][j] = dp[i][j - 1] + grid[i][j];
- 当左边和上边都是矩阵边界时: 即当 i = 0, j = 0时,其实就是起点,dp[i][j] = grid[i][j];
- 走到当前单元格(i, j)的最小路径和 = “从左方单元格(i, j - 1) 与上方单元格(i - 1, j)走来的 两个最小路径和中较小的” + 当前单元格值 grid[i][j]。具体分为以下 4 种情况:
- 初始状态:
- dp 初始化即可,不需要修改初始 0 值。
- 返回值:
- 返回 dp矩阵右下角值,即走到终点的最小路径和。
其实我们完全不需要建立 dp 矩阵浪费额外空间,直接遍历 grid[i][j] 修改即可。这是因为:grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];原grid矩阵元素中被覆盖为dp元素后(都处于当前遍历点的左上方),不会再被使用到。
这种方法是:不使用额外空间的动态规划
时间复杂度: O(mn),遍历整个grid矩阵元素。
空间复杂度: O(1),直接修改矩阵,不使用额外空间。
代码![在这里插入图片描述](https://img-blog.csdnimg.cn/20200616162548183.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzUyNTcxMA==,size_16,color_FFFFFF,t_70)
还可以采用:二维动态规划,即使用dp二维矩阵,空间和时间复杂度都为O(mn)。
还可以使用一维动态规划
转移方程:dp[j] = min(dp[j], dp[j - 1]) + grid(i, j),左边和上边都不生矩阵边界时适用,返回值为 dp[n - 1]
时间复杂度:O(mn)
空间复杂度:O(n),额外的一维数组,和一行大小相同