【LeetCode动态规划#16】矩阵的最小路径和、三角形的最小路径和

发布时间 2023-08-25 12:31:34作者: dayceng

矩阵的最小路径和

给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:一个机器人每次只能向下或者向右移动一步。

示例 1:

img
输入: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.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 100

代码与思路

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int row = grid.size();
        int col = grid[0].size();

        vector<vector<int>> dp(row + 1, vector<int>(col + 1, 0));
        //这里要初始化,并且也要遵循dp数组的含义
        //即:走到(i,j)时的最小路径和为dp[i][j]
        //因为走到一个方块只能从该方块的左边和上边过来
        //所以初始时上和左都是网格边界,没东西走过来,此时到起始点位的最小路径和就是当前点位的路径数值
        dp[0][0] = grid[0][0];
        //还是遵守“只能从上方和左边到达某个位置”的规律
        //于是有了下面三种情况,构成递推公式
        for(int i = 1; i < row; ++i){//网格最上方的路径和
            //到达(i,j)的最小路径和 = 到达(i - 1, j)的最小路径和 + i处的路径值
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for(int j = 1; j < col; ++j){//网格最左边的路径和
            dp[0][j] = dp[0][j - 1] + grid[0][j];
        }
        //上面两种情况有点像在初始化dp数组,但起始不完全是
        for(int i = 1; i < row; ++i){//网格内部
            for(int j = 1; j < col; ++j){
                //取从上方和左方中小的那一个座位更新值
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[row - 1][col - 1];
    }
};

三角形最小路径和

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 ii + 1

示例 1:

输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
   2
  3 4
 6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

示例 2:

输入:triangle = [[-10]]
输出:-10

提示:

  • 1 <= triangle.length <= 200
  • triangle[0].length == 1
  • triangle[i].length == triangle[i - 1].length + 1
  • -104 <= triangle[i][j] <= 104

思路

根据题意,我们还是只能往下或者往右遍历(即求某个位置的路径,只能从其上方或者左侧推导而来)

dp数组的含义仍然是:走到(i,j)时的最小路径和为dp[i][j]

题目要找的是"找出自顶向下的最小路径和",一般来说就会从上往下遍历三角形了,但是这样会有麻烦

三角形的顶点是唯一的,但底部边有很多个位置,这就意味着我们如果从从上往下遍历三角形最后会得到多条路径结果,然后还需要去选择哪一条的路径和最小

如果反着来,从三角形底部往上遍历,一开始就选中底部路径值最小的位置,这样就不需要再遍历结束后再选择最小路径了

代码

从三角形底部往上遍历

注意:是从底边再往上一层开始,也就是倒数第二层

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int layer = triangle.size(); // 获取三角形的层数
        vector<vector<int>> dp(layer + 1, vector<int>(layer + 1, 0));

        for (int i = layer - 1; i >= 0; --i) { // 从三角形的底部倒数第二层开始向上遍历
            for (int j = 0; j < triangle[i].size(); ++j) {//在层中从左往右遍历
                //最外层的for循环是使得遍历方向一直向上的
                //这里要取当前层和它的下一层之间的最小值来更新dp
                //比如,在最开始遍历的时候,是倒数第二层,此时还要去倒数第一层的对应位置查看dp值,取小的来更新dp
                dp[i][j] = min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j];
            }
        } // 从底层向顶层求最小路径和
        //求自顶向下的最小路径和,根据dp数组的含义就是求00处的dp值呗
        return dp[0][0];
    }
};