侧边栏壁纸
博主头像
thinkTV博主等级

喜爱动漫的二刺螈一枚,摩托车云爱好者(快要有车了)。 懂一点技术的在读生物医学工程研究生( •̀ ω •́ )✧,多多指教。

  • 累计撰写 127 篇文章
  • 累计创建 17 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

代码随想录算法训练营第三十九天 | 不同路径Ⅰ;不同路径 Ⅱ

thinkTV
2023-05-28 / 0 评论 / 0 点赞 / 90 阅读 / 1,036 字 / 正在检测是否收录...

1. 不同路径Ⅰ

代码随想录: 原文

力扣题目:62.不同路径

1.1 思路

动规五部曲

  1. 确定dp数组(dp table)以及下标的含义
  • dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径
  1. 确定递推公式
  • dp[i][j] = dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来
  1. dp数组的初始化
  • dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
  1. 确定遍历顺序
  • 递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
  • 这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的
  1. 举例推导dp数组

图片-1

1.2 代码实现

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];
    }
};

  • 时间复杂度:O(m×n)O(m × n)
  • 空间复杂度:O(m×n)O(m × n)

1.3 图论方法

  • 无论怎么走,走到终点都需要 m + n - 2 步
  • 在这m + n - 2 步中,一定有 m - 1 步是要向下走的,不用管什么时候向下走
  • 可以转化为,给你m + n - 2个不同的数,随便取m - 1个数,有几种取法

图片-1685271478394

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long numerator = 1; // 分子
        int denominator = m - 1; // 分母
        int count = m - 1;
        int t = m + n - 2;
        while (count--) {
            numerator *= (t--);
            while (denominator != 0 && numerator % denominator == 0) {
                numerator /= denominator;
                denominator--;
            }
        }
        return numerator;
    }
};

注意处理溢出的情况

2. 不同路径 Ⅱ

代码随想录: 原文

力扣题目:63. 不同路径 II

2.1 思路

  • 有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了

动规五部曲

  1. 确定dp数组(dp table)以及下标的含义

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

  1. 确定递推公式
  • dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
  • 因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)
if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候,再推导dp[i][j]
    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}

  1. dp数组初始化
  • 从(0, 0)的位置到(i, 0)的路径只有一条,所以dp[i][0]一定为1,dp[0][j]也同理
  • 如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0

图片-4

vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
  1. 确定遍历顺序
  • 从左到右一层一层遍历
  1. 举例推导dp数组

图片-5

代码实现

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
	if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) //如果在起点或终点出现了障碍,直接返回0
            return 0;
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
        for (int j = 0; j < n && obstacleGrid[0][j] == 0; 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];
    }
};

0

评论区