本次刷题日记的第 71 篇,力扣题为:931. 下降路径最小和,中等
一、题目描述:
931. 下降路径最小和,和之前做过的在岛屿上流水有点相似,一起来看看吧
二、这道题考察了什么思想?你的思路是什么?
931. 下降路径最小和 给我们带来了哪些值得关注的信息:
- 题目给出了一个 n*n 的二维数组, 数组中的元素都是整型数字,且数字没有规律,这里我们知道这里可以看做一定是一个正方形,宽高都是一样的 n
- 题目要求我们能够计算出从第一行的任意格子向下走动,直到走到最后一行的任意格子上,经历的路径和要是最小的
- 从上一行走到下一行,要求只能走
(row + 1, col - 1)
、(row + 1, col)
或者(row + 1, col + 1)
分析
其实我们看到这个已知信息,我一下子能够想到的就是之前咱们做过的岛屿的题目,也是这样的一个二维数组,但是岛屿的题目是流水,我们知道水一定是从高水位流向低水位的
但是今天咱们这个题并没有这个限制,相对来说,应该是要简单一些
按照题目中的下降逻辑,是这个样子的
咱们从第一行往下走,需要整个路径是最小的,那么是不是会很容易想到,第二行也走最小的,第三行也走最小的就可以了?
实际操作起来并不是这样的,例如,我们能从第 1 行的最小值开始走,但是到第 2 行的时候,我们可不一定就可以走最小的那个格子,例如这样
按照上述的这种方式的话,那么我们可能就要暴力求解了,每一条路径都要去计算,然后看看是不是最小的
其实我们好好思考一下,我们是不是可以倒着来看
最后一行选择哪个数,就看从第一行走下来的整体路径是最小的,然后再加上最后一行的数,最终得到路径最小的即可
我们不关心你如何走的,只关心第一行到最后一行的路径和是最小的即可
那么咱们,倒着走的话,可以是这样的
那么其实接下来就是一个动态规划的处理方式了
我们可以定义一个帮助数组,是一个二维数组,里面的元素含义表示从第一行走到当前位置最小的路径和
那么是不是就有如下公式
help[i][j] = matrix[i][j]+min(dp(i−1,j−1),dp(i−1,j),dp(i−1,j+1))help[i][j] = matrix[i][j] + min(dp(i-1,j-1), dp(i-1,j), dp(i-1,j+1)) help[i][j]=matrix[i][j]+min(dp(i−1,j−1),dp(i−1,j),dp(i−1,j+1))
根据题目的提示我们知道,给出的二维数组的行列 n 以及里面具体的数字是有限制的
因此
- 咱们可以初始化 help 数组,里面的每一个元素为 10001 ,一定是最大的一个值
- 咱们还可以初始化 help 数组的第一行,一定是和 matrix 数组的第一行一样的
- 那么,接下来,咱们就可以写代码倒推了
举个例子,看题目中的示例 1
对应到咱们的 help 数组就是这个样子的
因此,咱们看最后一行的数据,就知道该题目的最小路径和为多少了
三、编码
根据上述逻辑和分析,我们就可以翻译成如下代码
- 此处需要注意先初始化好 help 数组,且做好初始数据的处理
- 采用倒推的方式来进行处理
编码如下:
func minFallingPathSum(matrix [][]int) int { // 初始化帮助数组 help help := make([][]int , len(matrix)) for i:=0; i<len(matrix); i++ { help[i] = make([]int, len(matrix[i])) for j :=0; j<len(matrix[i]); j++ { help[i][j] = 10001 } } // 初始化 help 的第一行的数据 for i:=0; i<len(matrix); i++ { help[0][i] = matrix[0][i] } // 开始定义 dp ,然后从下往上找 var dp func(i,j int) int dp = func(i,j int) int { // 处理边界问题 if i<0 || i >= len(matrix) || j<0 || j>=len(matrix[0]) { return 10001 } // 如果传入的是第一行 if i == 0 { return matrix[0][j] } // 如果传入的是其他行,则校验是否在 help 中有计算过值 if help[i][j] != 10001 { return help[i][j] } help[i][j] = matrix[i][j] + min(dp(i-1,j-1), dp(i-1,j), dp(i-1,j+1)) return help[i][j] } var res int = 10001 for j:=0; j<len(matrix[0]); j++{ // 咱们这里直接取最后一行的最小值即可 res = min(res, dp(len(matrix)-1, j)) } return res } func min(nums... int) int { min := 10001 for _, num := range nums { if min > num { min = num } } return min }
四、总结:
按照我们这种的处理方式,时间复杂度为 O(n^2) , 咱们遍历了给出的二维数组的所有节点
空间复杂度也是 O(n^2) ,咱们引入了一个 help 二维数组来帮我们记录最小路径和
原题地址:931. 下降路径最小和
今天就到这里,学习所得,若有偏差,还请斧正
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞关注收藏,下次见~