动态规划2

62.不同路径

5步走:

1.dp代表的是:dpij表示到【i,j】一共有几种路径

2.表达式:

想要求dpij,只能有两个方向来推导出来,即dpi - 1j 和 dpij - 1。

此时在回顾一下 dpi - 1j 表示啥,是从(0, 0)的位置到(i - 1, j)有几条路径,dpij - 1同理。

那么很自然,dpij = dpi - 1j + dpij - 1,因为dpij只有这两个方向过来。

3.初始化:

dp10=1;

首先dpi0一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp0j也同理。

所以初始化代码为:

复制代码
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;

4.这里要看一下递推公式dpij = dpi - 1j + dpij - 1,dpij都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。

这样就可以保证推导dpij的时候,dpi - 1j 和 dpij - 1一定是有数值的。

cpp 复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for (int i = 0; i < m; i++) dp[i][0] = 1;
        for (int j = 0; j < n; j++) dp[0][j] = 1;
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
};

❓ 问题 2:vector<vector<int>> dp(m, vector<int>(n, 0)); 是什么意思?

这行代码是 C++ 中**创建并初始化一个二维数组(矩阵)**的标准写法。我们可以像"剥洋葱"一样从外到内看:

  • 最外层 :vector<vector<int>> dp(m, ...)

    表示创建一个名为 dp 的容器,它里面要放 m 个元素(代表有 m 行)。

  • 内层 :vector<int>(n, 0)

    这是用来初始化每一行的"模板"。它表示创建一个有 n 个整数的一维数组,并且把所有整数都初始化为 0。

连起来 :最终生成了一个 m 行 n 列的表格(网格),里面的所有格子初始值都是 0。

(例如 m=3, n=5,就是一个 3 行 5 列的矩阵,共 15 个格子全为 0)。


❓ 问题 1:为什么 i/j 有 0 有 1?为什么从 1 开始?为什么最后是 m-1, n-1?

这涉及到数组下标 和动态规划的边界条件。我用"表格走格子"帮你形象理解:

1. 为什么会有 i=0 和 j=0 的初始化?

在 m x n 的网格中(设 m=行数,n=列数):

  • 第 0 行(最上面一行) :机器人只能一直向右 走,只有 1 种走法。

  • 第 0 列(最左边一列) :机器人只能一直向下 走,也只有 1 种走法。

所以代码先用两个循环,把边界上的所有格子都设置为 1:

cpp

复制代码
for (int i = 0; i < m; i++) dp[i][0] = 1; // 把最左边一列全设为1
for (int j = 0; j < n; j++) dp[0][j] = 1; // 把最上边一行全设为1

这一步是动态规划的"地基",没有它们,后续的推导就无法进行。

2. 为什么双层循环要从 i=1 和 j=1 开始?

因为除了第一行和第一列,任何一个格子 (i, j) 的走法,只取决于它"左边格子"和"上边格子"的走法之和 ,即:

dp[i][j] = dp[i-1][j](上边) + dp[i][j-1](左边)

  • 如果你从 i=0 开始,那么 i-1 就是 -1,数组越界,程序直接崩溃。

  • 如果你从 j=0 开始,那么 j-1 就是 -1,同样会越界。

所以,必须从 第 1 行 和 第 1 列(也就是表格的第二行第二列)开始计算,才能安全地引用"上边"和"左边"的数值。

3. 为什么最后返回的是 dp[m - 1][n - 1]?

因为数组的下标是从 0 开始数的:

  • 如果网格有 m 行,那么最后一行的下标是 m - 1。

  • 如果网格有 n 列,那么最后一列的下标是 n - 1。

终点在右下角,所以自然就是 dp[m - 1][n - 1]。

63. 不同路径 II

有障碍物,

dpij :表示从(0 ,0)出发,到(i, j) 有dpij条不同的路径。

递推公式和62.不同路径一样,dpij = dpi - 1j + dpij - 1。

cpp 复制代码
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
         int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        vector<vector<int>>dp(m,vector<int>(n,0));
       
        if(m<1||n<1)return 1;
        for(int i=0;i<m&&obstacleGrid[i][0]!=1;i++){
            dp[i][0]=1;
        }
        for(int j=0;j<n&&obstacleGrid[0][j]!=1;j++){
            dp[0][j]=1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                if(obstacleGrid[i][j]==1)continue;
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
};
相关推荐
NEFU_Jyj9 小时前
牛客周赛R168
算法
Navigator_Z17 小时前
LeetCode //C - 1317. Convert Integer to the Sum of Two No-Zero Integers
c语言·算法·leetcode
D e re k ZH17 小时前
C++ 标准库算法全景指南
数据结构·c++·算法
冻柠檬飞冰走茶18 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
雪落漂泊18 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法
LabVIEW开发20 小时前
LabVIEW 连接板:28 个端子怎么排,优先级怎么定
java·算法·labview
严肃小白兔1 天前
MATLAB 数值计算中的精度与误差问题:浮点运算、误差传播与数值稳定性
人工智能·算法·matlab
青少儿编程课堂1 天前
蓝桥杯青少组图形化省考报名倒计时·全国青少年信息素养大赛·电子学会图形化考级:校园黑白棋人机对战解析
c++·python·算法·bfs·信息学竞赛
jktantan1 天前
注解式脱敏:用 Jackson 的 ContextualSerializer 做字段级策略(一)
spring boot·后端·算法·spring cloud·系统架构