一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
一.题目:
931. 下降路径最小和 给你一个
n x n的 方形 整数数组matrix,请你找出并返回通过matrix的下降路径 **的 ****最小和 。
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col +1) 。
示例 1:
输入: matrix = [[2,1,3],[6,5,4],[7,8,9]]
输出: 13
解释: 如图所示,为和最小的两条下降路径
示例 2:
输入: matrix = [[-19,57],[-40,-5]]
输出: -59
解释: 如图所示,为和最小的下降路径
提示:
n == matrix.length == matrix[i].length1 <= n <= 100-100 <= matrix[i][j] <= 100
二、思路分析:
首先,题目要求我们求出从顶部到底部的最小路径和,而每次往下走只能从正下或者对角线往下走,一直到方形的底部求出最小的路径和。对于这种问题,一般采取动态规划的思想,因为他符合动态规划要求的一切,最终结果也是需要最值问题。
- 首先我们确立动态规划的
base case,由于我们题目要求从上往下走,而且不限于从[0,0]开始走,所以我们的base case就能够确定为第一行的所有元素值,如果目标是第一行的元素直接返回元素值即可。 - 接下来是状态转移方程,由于我们需要找到底部的最小路径和的值,而底部的路径和的值是由它的
上方、左上方和右上方决定的,只需要找到这三个路径和的最小值即可。而这它的前三个值则是由它之前的值决定的,这就是重叠子问题和最优子结构决定的。 - 除此之外,我们需要创建一个
备忘录,因为存在重叠子问题我们可以复用结果,最终我们返回的结果是要找到最后一排的任何位置,且是最小值即可。
三、代码:
/**
* @param {number[][]} matrix
* @return {number}
*/
var minFallingPathSum = function (matrix) {
function dp(matrix, i, j) {
//非法索引
if (i < 0 || j < 0 || i >= matrix.length || j >= matrix[0].length) return 66666
//base case
if (i == 0) return matrix[0][j]
if(memo[i][j] !== 666)return memo[i][j]
//状态转移方程
memo[i][j] = matrix[i][j] + Math.min(dp(matrix,i-1,j-1),
dp(matrix,i-1,j),dp(matrix,i-1,j+1))
return memo[i][j]
}
//先将所有数值初始化
let n = matrix.length
let intialValue = 666
let memo = new Array(n).fill(intialValue).map(() => new Array(n).fill(intialValue))
let res = Number.MAX_SAFE_INTEGER
//终点可能在最后一排的任何位置
for(let j=0 ; j<n ; j++){
res = Math.min(res,dp(matrix,n-1,j))
}
return res
};
四、总结:
总的来说,一般涉及最值得问题,如果里面由重叠子问题和最优子结构的结构都需要考虑利用
动态规划进行求解,动态规划最重要的就是base case,状态转移方程,只要明确了状态转移方程基本上动态规划就没问题了。