这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
最小路径和(题号64)
题目
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。

示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:
输入:grid = [[1,2,3],[4,5,6]]
输出:12
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 2000 <= grid[i][j] <= 100
链接
解释
这题啊,这题是经典动态规划。
虽然是中等题吧,但笔者感觉它不配。
DP嘛,先搞它一个双层数组,数量和grid保持一致就好了,完事之后开始进行初始化数据的赋值,首先第一行可以搞出来,因为第一行没有上面的元素,所以只能从左侧走,那这就很简单了:
for (let i = 0; i < n; i++) {
dp[0][i] = i ? grid[0][i] + dp[0][i - 1] : grid[0][i]
}
现在也可以处理下第一列,不过感觉没必要,放在循环里面也可以的,这里暂不处理。
那么接下来就是搞出来DP公式,这里的公式没有多复杂的逻辑,要想到达一个块,只能从这个块的上面或者左边走过来,取最小值即可,那么当前块的最少路径就是刚才求到的最小值加上当前块的值,也就是:
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + gird[i][j]
对吧,十分简单,现在别忘了还需要处理下每一列第一个块的问题,因为这些块的左侧是没有元素的,所以只能从上一列的第一块走下来,所以这些块的值是:
dp[i][j] = dp[i - 1][j] + grid[i][j]
那么此时就可以通过两层循环来拿到所有的dp值,然后根据题意,选最后一个就完事了。
至此,简单的动态规划就完成了,下面看看代码。
自己的答案(双数组)
var minPathSum = function(grid) {
const m = grid.length
const n = grid[0].length
const dp = Array.from({length: m}, () => new Array(n).fill(0))
for (let i = 0; i < n; i++) {
dp[0][i] = i ? grid[0][i] + dp[0][i - 1] : grid[0][i]
}
for (let i = 1; i < m; i++) {
for (let j = 0; j < n; j++) {
if (!j) {
dp[i][j] = dp[i - 1][j] + grid[i][j]
} else {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
}
}
}
return dp[m - 1][n - 1]
};
这一块的逻辑和解释中说的一样,没有区别,此时的时间可以到90%,内存消耗在70%左右,证明在空间复杂度上还有优化空间,这里的优化也是经典的动态规划降维优化👇。
自己的答案(降维)
上面说了要降低空间复杂度,那么最经典的做法就是将DP数组从二维降到一维,这是完全可行的,并且非常简单。
回到题目,每个块的最小值只和它上边和左边的块有关系,那么完全可以只维护一个一维数组,每次都将这个数组当作上面一行即可,然后从左边开始更新,这样当前位置的左边的值可以当作这一行的值,后面的值当作上一行的值,如此即可。
var minPathSum = function(grid) {
const m = grid.length
const n = grid[0].length
const dp = new Array(n)
for (let i = 0; i < n; i++) {
dp[i] = (i ? dp[i - 1] : 0) + grid[0][i]
}
for (let i = 1; i < m; i++) {
for (let j = 0; j < n; j++) {
dp[j] = (j ? Math.min(dp[j - 1], dp[j]) : dp[j]) + grid[i][j]
}
}
return dp[n - 1]
};
如此即可用一维数组来解决这个问题,最后的答案就是DP数组的最后一个元素,在这段代码的两个for循环里面有一个判断j是否存在的代码,这里的这个逻辑就不能提出来了,因为每一行的第一个元素都需要实时计算,这也是和上面解法的不同之处。
更好的方法
无
PS:想查看往期文章和题目可以点击下面的链接:
这里是按照日期分类的👇
经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇