【刷题日记】931. 下降路径最小和

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

本次刷题日记的第 71 篇,力扣题为:931. 下降路径最小和 ,中等

一、题目描述:

931. 下降路径最小和,和之前做过的在岛屿上流水有点相似,一起来看看吧

二、这道题考察了什么思想?你的思路是什么?

931. 下降路径最小和 给我们带来了哪些值得关注的信息:

  • 题目给出了一个 n*n 的二维数组, 数组中的元素都是整型数字,且数字没有规律,这里我们知道这里可以看做一定是一个正方形,宽高都是一样的 n
  • 题目要求我们能够计算出从第一行的任意格子向下走动,直到走到最后一行的任意格子上,经历的路径和要是最小的
  • 从上一行走到下一行,要求只能走 (row + 1, col - 1)(row + 1, col) 或者 (row + 1, col + 1)

分析

其实我们看到这个已知信息,我一下子能够想到的就是之前咱们做过的岛屿的题目,也是这样的一个二维数组,但是岛屿的题目是流水,我们知道水一定是从高水位流向低水位的

但是今天咱们这个题并没有这个限制,相对来说,应该是要简单一些

按照题目中的下降逻辑,是这个样子的

咱们从第一行往下走,需要整个路径是最小的,那么是不是会很容易想到,第二行也走最小的,第三行也走最小的就可以了?

实际操作起来并不是这样的,例如,我们能从第 1 行的最小值开始走,但是到第 2 行的时候,我们可不一定就可以走最小的那个格子,例如这样

按照上述的这种方式的话,那么我们可能就要暴力求解了,每一条路径都要去计算,然后看看是不是最小的

其实我们好好思考一下,我们是不是可以倒着来看

最后一行选择哪个数,就看从第一行走下来的整体路径是最小的,然后再加上最后一行的数,最终得到路径最小的即可

我们不关心你如何走的,只关心第一行到最后一行的路径和是最小的即可

那么咱们,倒着走的话,可以是这样的

那么其实接下来就是一个动态规划的处理方式了

我们可以定义一个帮助数组,是一个二维数组,里面的元素含义表示从第一行走到当前位置最小的路径和

那么是不是就有如下公式

h e l p [ i ] [ j ]   =   m a t r i x [ i ] [ j ] + m i n ( d p ( i 1 , j 1 ) , d p ( i 1 , j ) , d p ( 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. 下降路径最小和

今天就到这里,学习所得,若有偏差,还请斧正

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~

猜你喜欢

转载自juejin.im/post/7111717835228872712
今日推荐