矩阵的最小路径和
一、题目
给定一个包含非负整数的 m x n 网格 grid,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
leetcode:https://leetcode.cn/problems/minimum-path-sum/
类似题目,不同路径:https://leetcode.cn/problems/unique-paths/
二、思路
典型的动态规划类题目,最终要走到右下角,这个矩阵长为 m,宽为 n。右下角为 [m-1, n-1] 位置,每一次只能走一步,那就要不是 [m-2, n-1] 走过来的,要不就是 [m-1, n-2] 走过来的,所以 [m-1, n-1] 的值应该为 std::min(arr[m-2, n-1], arr[m-1, n-2]) + 1
。因此我们每一步需要选择最小的路径来走就好了。
第一行和第一列只能横着走,或者只能竖着走。所以只能填充原始数组即可。所以我们还是申请的是和原二维数组一样大小的数组,并且填充第一行和第一列。其他行和列,每次取最小路径即可。
三、code
1 | class Solution { |
时间复杂度:O(m * n)
,空间复杂度:O(m * n)
三、空间压缩
我们可以将空间复杂度压缩到 min{M,N}
假如本题目的矩阵如下:
1 | 1 3 5 |
我们生成一个长度为 3 的数组。
在第一次遍历时,我们给数组填上 {1, 4, 9}
,代表的意思是 arr[0]: dp[0][0], arr[1]: dp[0][1], arr[2]: dp[0][2]
。
好,我们开始第二次遍历,第二次遍历,我们希望求出 dp[1][0], dp[1][1], dp[1][2]
。
- 而
dp[1][0] = dp[0][0]+grid[1][0]
,我们把dp[1][0]
赋给arr[0]
。 - 接着
dp[1][1] = min{dp[1][0],dp[0][1]}+grid[1][1]
,而此时dp[0][1]
就是上一次遍历中求得的arr[1]
,dp[1][0]
我们刚才已经求出来的,就是arr[0]
,于是我们把dp[1][1]
赋给arr[1]
dp[1][2] = min{dp[1][1], dp[0][2]}+grid[1][2]
,和dp[1][1]
的求法一致,之后赋给arr[2]
之后,我们再开始遍历。继续给 arr 赋值。我们发现,整个过程其实就是不断滚动更新 arr 数组,让 arr 依次变成 dp 矩阵每一行的值,最终变成 dp 矩阵最后一行的值。
还有一个细节需要注意,
- 如果给定的矩阵列数小于行数,那么 arr 数组的长度与矩阵列的长度一致
- 如果给定的矩阵行数小于列数,那么 arr 数组的长度与矩阵行的长度一致。然后 arr 更新为 dp 矩阵每一列的值,从左向右滚动过去。
1 | class Solution2 { |
时间复杂度:O(M*N)
,空间复杂度:O(min{M, N})