Day34-动态规划,leetcode62,63

  1. 不同路径
  • 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
  • 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
  • 问总共有多少条不同的路径?

  • 思路
  • 1.确定dp数组及下标含义:dp[i][j],表示从(0,0)出发,到(i,j)有dp[i][j]条不同的路径
  • 2.确定递推公式,dp[i][j],只能从两个方向推导,即dp[i-1][j],dp[i][j-1],dp[i][j] = dp[i-1][j] + dp[i][j-1]
  • 3.dp数组初始化,dp[i][0]=1,因为从(0,0)出发到(i,0)位置只有一条路径,因为只能向右走,dp[0][j]=1,从(0,0)出发到(0,j)位置只有一条路径,因为只能向下走
  • 4.确定遍历顺序,dp[i][j] = dp[i-1][j] + dp[i][j-1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
  • 5.举例推导dp数组
/**
1. dp数组定义:dp[i][j] 表示从起点到 (i, j) 的不同路径数。
2. 初始化:第一行和第一列都只有1种走法(只能一直向右或一直向下)。
3. 状态转移公式:dp[i][j] = dp[i-1][j] + dp[i][j-1],即当前位置的路径数等于上方和左方的路径数之和。
4. 遍历顺序:从左到右、从上到下依次填充整个 dp 数组。
5. 返回结果:返回右下角 dp[m-1][n-1],即所有路径数。

用动态规划,递推填表,最后返回右下角的路径数。
 */
var uniquePaths = function(m, n) {
    // 1. 创建 m 行 n 列的 dp 数组
    const dp = Array(m).fill().map(item => Array(n));

    // 2. 初始化第一列,每个位置只能从上面下来,只有1种走法
    for (let i = 0; i < m; ++i) {
        dp[i][0] = 1;
    }

    // 3. 初始化第一行,每个位置只能从左边过来,只有1种走法
    for (let i = 0; i < n; ++i) {
        dp[0][i] = 1;
    }

    // 4. 状态转移:每个格子的路径数 = 上方格子路径数 + 左侧格子路径数
    for (let i = 1; i < m; ++i) {
        for (let j = 1; j < n; ++j) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }
    // 5. 返回右下角的路径数
    return dp[m - 1][n - 1];
};
var uniquePaths = function(m, n) {
    let dp = new Array(m).fill(1).map(() => new Array(n).fill(1));
    // dp[i][j] 表示到达(i,j) 点的路径数
    for (let i=1; i<m; i++) {
        for (let j=1; j< n;j++) {
            dp[i][j]=dp[i-1][j]+dp[i][j-1];
        }
    }
    return dp[m-1][n-1];

};
  1. 不同路径 II
  • 给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0])。机器人尝试移动到 右下角(即 grid[m - 1][n - 1])。机器人每次只能向下或者向右移动一步。
  • 网格中的障碍物和空位置分别用 1 和 0 来表示。机器人的移动路径中不能包含 任何 有障碍物的方格。
  • 返回机器人能够到达右下角的不同路径数量。
  • 测试用例保证答案小于等于 2 * 109。

  • 思路
  • 1.确定dp数组及下标含义:dp[i][j],表示从(0,0)出发,到(i,j)有dp[i][j]条不同的路径
  • 2.确定递推公式,dp[i][j],只能从两个方向推导,考虑障碍物情况,obstacleGrid[i][j] == 0,即当(i, j)没有障碍的时候,再推导dp[i][j],即dp[i-1][j],dp[i][j-1],dp[i][j] = dp[i-1][j] + dp[i][j-1]
  • 3.dp数组初始化,obstacleGrid[i][0] == 0 && dp[i][0]=1,因为从(0,0)出发到(i,0)位置只有一条路径,因为只能向右走,obstacleGrid[0][j] == 0 && dp[0][j]=1,从(0,0)出发到(0,j)位置只有一条路径,因为只能向下走。这里要考虑障碍物的存在,障碍物之后的位置不是1,是0或者空。
  • 4.确定遍历顺序,dp[i][j] = dp[i-1][j] + dp[i][j-1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
  • 5.举例推导dp数组
/**
1. dp数组定义:dp[i][j] 表示到达 (i, j) 的路径数。
2. 初始化:
  第一行/列只要没遇到障碍物,路径数都是1,遇到障碍物后后面全为0。
3. 状态转移:
  如果当前位置是障碍物(obstacleGrid[i][j] === 1),路径数为0;
  否则,dp[i][j] = dp[i-1][j] + dp[i][j-1]。
4. 返回结果:右下角的路径数 dp[m-1][n-1]。

动态规划,遇到障碍物路径数为0,否则等于上方和左方路径数之和,最后返回右下角的路径数。
 */
var uniquePathsWithObstacles = function(obstacleGrid) {
    const m = obstacleGrid.length;
    const n = obstacleGrid[0].length;
    const dp = Array(m).fill().map(item => Array(n).fill(0)); // dp[i][j] 表示到达 (i, j) 的路径数

    // 初始化第一列:只要没遇到障碍物,路径数都是1,遇到障碍物后全为0
    for (let i = 0; i < m && obstacleGrid[i][0] === 0; ++i) {
        dp[i][0] = 1;
    }

    // 初始化第一行:同理
    for (let i = 0; i < n && obstacleGrid[0][i] === 0; ++i) {
        dp[0][i] = 1;
    }

    // 状态转移
    for (let i = 1; i < m; ++i) {
        for (let j = 1; j < n; ++j) {
            // 如果当前位置是障碍物,路径数为0,否则等于上方和左方路径数之和
            dp[i][j] = obstacleGrid[i][j] === 1 ? 0 : dp[i - 1][j] + dp[i][j - 1];
        }
    }

    return dp[m - 1][n - 1]; // 返回右下角的路径数
};



参考&感谢各路大神

posted @ 2025-06-30 09:51  安静的嘶吼  阅读(6)  评论(0)    收藏  举报