leetcode 64最小路径和

一、完整代码(精简注释)

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

        // dp[i][j] 表示到达 (i,j) 的最小路径和
        vector<vector<int>> dp(row, vector<int>(col, 0));

        // 初始化起点
        dp[0][0] = grid[0][0];

        // 初始化第一列,只能从上方到达
        for (int i = 1; i < row; i++) {
            dp[i][0] = grid[i][0] + dp[i-1][0];
        }

        // 初始化第一行,只能从左方到达
        for (int j = 1; j < col; j++) {
            dp[0][j] = grid[0][j] + dp[0][j-1];
        }

        // 从上方和左方选择较小的路径和
        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];
    }
};

二、动态规划五步总结

1. 确定 dp 数组及下标含义

dpij 表示从左上角 (0,0) 出发,到达位置 (i,j) 时的最小路径和。

例如:

dp23 表示从 (0,0) 到 (2,3) 的最小路径和。

注意:dp 数组记录的是到达当前位置的最小路径和,而不是当前位置的原始数值。

2. 确定状态转移方程

题目规定只能向右或者向下移动。

因此,到达当前位置 (i,j) 只有两种方式:

  • 从上方 (i-1,j) 向下移动。

  • 从左方 (i,j-1) 向右移动。

为了得到最小路径和,需要比较上方和左方的路径和,选择较小的一个,再加上当前位置的数值。

状态转移方程:

复制代码
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j];

其中:

  • dpi-1j:从上方到达的最小路径和。

  • dpij-1:从左方到达的最小路径和。

  • gridij:当前位置的数值。

核心思想:当前位置的最优解,由上方和左方已经计算好的最优解推导得到。

3. 初始化 dp 数组

由于第一行和第一列只有一种移动方向,因此需要单独初始化。

(1)初始化起点

复制代码
dp[0][0] = grid[0][0];

(2)初始化第一列

复制代码
for (int i = 1; i < row; i++) {
    dp[i][0] = grid[i][0] + dp[i-1][0];
}

第一列只能从上往下移动,因此当前值等于上方路径和加上当前位置的数值。

(3)初始化第一行

复制代码
for (int j = 1; j < col; j++) {
    dp[0][j] = grid[0][j] + dp[0][j-1];
}

第一行只能从左往右移动,因此当前值等于左方路径和加上当前位置的数值。

4. 确定遍历顺序

复制代码
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];
    }
}

遍历顺序:从上到下、从左到右。

原因:

计算 dpij 时,需要使用上方的 dpi-1j 和左方的 dpij-1。

因此必须保证这两个位置已经计算完成。

由于第一行和第一列已经初始化,所以剩余位置从 (1,1) 开始遍历即可。

5. 举例推导 dp 数组

假设原始数组:

复制代码
grid:
1 3 1
1 5 1
4 2 1

第一步:初始化起点、第一行和第一列。

复制代码
dp:
1 4 5
2 ? ?
6 ? ?

第二步:计算剩余位置。

复制代码
dp[1][1] = min(4, 2) + 5 = 7;
dp[1][2] = min(5, 7) + 1 = 6;
dp[2][1] = min(7, 6) + 2 = 8;
dp[2][2] = min(6, 8) + 1 = 7;

最终得到:

复制代码
dp:
1 4 5
2 7 6
6 8 7

因此最小路径和为 7。

对应路径:

复制代码
1 -> 3 -> 1 -> 1 -> 1

三、复杂度分析

时间复杂度:O(m * n)

因为需要遍历整个二维数组,每个位置只计算一次。

空间复杂度:O(m * n)

因为创建了一个 m 行 n 列的二维 dp 数组存储路径和。

四、核心总结

  1. 本题属于二维动态规划中的网格路径问题。

  2. dpij 表示从起点到当前位置的最小路径和。

  3. 第一行只能从左边到达,第一列只能从上边到达,因此需要单独初始化。

  4. 对于其他位置,只需要比较上方和左方的最小路径和,选择较小值,再加上当前位置的数值。

  5. 遍历顺序为从上到下、从左到右,保证计算当前位置时,所依赖的状态已经计算完成。

  6. 最终返回 dprow-1col-1,即从左上角到右下角的最小路径和。

与「不同路径」的区别

不同路径:

复制代码
dp[i][j] = dp[i-1][j] + dp[i][j-1];

计算的是到达当前位置的路径总数。

最小路径和:

复制代码
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j];

计算的是到达当前位置的最小路径代价。

最终记忆:不同路径求方案数量,最小路径和求最优代价。两者都是通过上方和左方的状态推导当前位置的状态。

相关推荐
光影少年1 小时前
AI Agent、自动化与未来工作
人工智能·算法·架构
牧羊人.3331 小时前
计算机视觉基础 第16章|EigenFace,FisherFace,LBPH传统人脸识别算法
人工智能·算法·计算机视觉
考研保研资料分享1 小时前
双非新闻学保研复盘:东华小组展示、长安面试与兰大预推免
面试·职场和发展
Nil2081 小时前
leetcode 72编辑距离
算法·leetcode·职场和发展
神工坊2 小时前
技术分享︱SIMFORGE HSF® 网格加密与热点加速技术实践
算法·hpc·网格·cae·工程仿真·数值引擎·samr
Nil2082 小时前
leetcode 136只出现一次的数字
leetcode·哈希算法·散列表
CV@CV2 小时前
世界模型与智能体协同推理逻辑
人工智能·算法·边缘计算·量子计算·具身智能
jiayoushijie-泽宣2 小时前
SHIFT-PathFormer:专家轨迹蒸馏、连续安全优化与超大迷宫实验
算法
猿究院_夏燊3 小时前
SpringMVC 到底是怎么干活的?
java·网络·职场和发展