【动态规划】LeetCode-931.下降路径最小和

🎈算法那些事专栏说明:这是一个记录刷题日常的专栏,每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目,在这立下Flag🚩

🏠个人主页:Jammingpro

📕专栏链接:算法那些事

🎯每日学习一点点,技术累计看得见

题目

题目描述

给你一个 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].length

1 <= n <= 100

-100 <= matrix[i][j] <= 100

题解

题目中说到:在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。这句话说的是,第i行第j列的元素,可以到达第i+1行第j-1列、第i+1行第j列、第i+1行第j+1列元素。如下图左图所示,第0行第1列元素可以到达第1行第0列、第1行第1列、第1行第2列元素。也就是说,当前元素向下走时,可以向左下走、向下走或者向右下走。反过来说,到达第i行第j列的上一步可以是第i-1第j-1列、第i-1行第j列、第i-1行第j+1列,如下图右图所示。

题目中所说的最小路径是指:从第0行的任意一个元素出发,每一步向左下、向下或向右下走1步,一直到达最后一行,将上述每一步到达的元素相加后,得最小和。我们可以使用一个dp表(二维数组)保存到达第i行第j列的最小路径和。因为第0行是出发点,所以dp[0][i]=matrix[0][i]。如下图所示(下图显示的内容为示例1)↓↓↓

余下第i行第0列的元素只能从上面一个元素或者从右上元素到达,因为左上元素不存在,故dp[i][0]=min(dp[i-1][j],dp[i-1][j+1])+matrix[i][0]。以示例1为例,计算第1行第0列元素示意图如下↓↓↓

与下第i行最后一列元素之恶能从上面一个元素或者从左上元素到达,因为右上元素不存在,故dp[i][最后一个元素下标]=min(dp[i-1][j-1],dp[i-1][j])+matrix[i][最后一个元素下标]。以示例1为例,计算第1行最后一个元素示意图如下↓↓

每一行总非第1个元素和最后一个元素,均可以由左上、上、右上元素向下一步到达,故dp[i][j]=min(dp[i-1][j-1], min(dp[i-1][j], dp[i-1][j+1]))+matrix[i][j]。以示例1为例,计算第1行下标为1的元素示意图如下↓↓

因为我们计算到达第i行的最小路径和时,需要知道第i-1行的最小路径和,因此,我们的计算需要从上到下。经过上面的分析,我们可以得到如下代码↓↓↓

cpp 复制代码
class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {
            int n = matrix.size();
            vector<vector<int>>dp(n, vector<int>(n));
            for(int i = 0; i < n; i++)
                dp[0][i] = matrix[0][i];
            for(int i = 1; i < n; i++)
            {
                dp[i][0] = min(dp[i - 1][0], dp[i - 1][1]) + matrix[i][0];
                dp[i][n - 1] = min(dp[i - 1][n - 2], dp[i - 1][n - 1]) + matrix[i][n - 1];
                for(int j = 1; j < n - 1; j++)
                    dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i - 1][j + 1])) + matrix[i][j];
            }
            int ret = INT_MAX;
            for(int i = 0; i < n; i++)
                ret = min(ret, dp[n - 1][i]);
            return ret;
    }
};

上面代码中需要额外考虑每一行的第1个元素和最后1个元素,还需要额外考虑第1行。我们可以通过对dp表多开辟1行2列,来避免额外考虑上述内容。dp表第0行初始化为0,这样不会影响第1行元素的计算,因为min(dp[i-1][j-1],min(dp[i-1][j],dp[i-1][j+1]))的值始终为0。而第0列和最后一列初始化为INT_MAX(int类型所能表示的最大值),这样在计算min(dp[i-1][j-1],min(dp[i-1][j],dp[i-1][j+1]))时,始终不可能选到INT_MAX所在的那一个元素,因为其数值最大。新开辟的dp表示意图如下,下图标注的※号位置对应于上述代码的dp表↓↓↓

通过dp增开1行2列后的代码如下,其代码行数有所缩减↓↓↓

cpp 复制代码
class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {
        int n = matrix.size();
        vector<vector<int>>dp(n + 1, vector<int>(n + 2, INT_MAX));
        for(int i = 0; i <= n + 1; i++)
            dp[0][i] = 0;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i - 1][j + 1])) + matrix[i - 1][j - 1];
        int ret = INT_MAX;
        for(int i = 1; i <= n; i++)
            ret = min(ret, dp[n][i]);
        return ret;
    }
};

本文存在不足,欢迎留言或私信批评、指正。希望我的解决方法能够对你有所帮助~~

今日打卡完成,点亮小星星☆→★

相关推荐
hsling松子1 小时前
使用PaddleHub智能生成,献上浓情国庆福
人工智能·算法·机器学习·语言模型·paddlepaddle
dengqingrui1232 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝2 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O3 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
CV-King3 小时前
opencv实战项目(三十):使用傅里叶变换进行图像边缘检测
人工智能·opencv·算法·计算机视觉
代码雕刻家3 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
雨中rain3 小时前
算法 | 位运算(哈希思想)
算法
Kalika0-05 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
sp_fyf_20245 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
我是哈哈hh7 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝