一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。

思路
本题在上一题 不同路径 上增加了一个条件,不同路径 中不存在障碍物,而 不同路径 II 则存在障碍物,有障碍物时机器人无法通过且无法到达有障碍物的格子(意味着如果起点就有障碍物,那么机器人就无法行走),行走方式依旧是 往下和往右 ,因此到达某一个格子的不同路径数和上面 dp[i - 1][j] 与 左边 dp[i][j - 1] 相关。但想必你一定想得到,有障碍物的格子既然走不了,那对应位置的格子要怎么求其 dp[i][j] ?
某个格子上如果有障碍物,那么机器人一定永远都到达不了该格子,那么到达该格子的不同路径数就为 0,这会不会影响下面 dp[i][j]的求解呢?我们纸上演示一下便知:

可以清晰地看到,一个障碍物会影响 dp[i][j] 的来源,如果障碍物挡住了任意一个来源,那么该来源的不同路径数就为 0。
举个栗子,对于第三行第三列的格子来说,到达此格子机器人只能是从左边相邻的格子过来,上面的格子被障碍物挡住机器人无法穿过,因此 到达第三行第三列的格子的 不同路径数 取左边格子的不同路径数即可,而为了满足下面的递推公式,将有障碍物处的 dp[i][j] 设为 0 即可。
下面用动态规划五部曲细解。
确定 dp 数组的含义
本题 dp 数组含义和 不同路径 是一样的,代表机器人到达第 i + 1 行第 j + 1 列的格子处的不同路径数为 dp[i][j]。
确定递推公式
有了 不同路径 作为铺垫,本题的递推公式就很简单了,上面的思路中,为了使得递推公式排除障碍物的影响,我们将有障碍物的对应位置的 不同路径数 赋值为 0,这样就无需改动递推公式:
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
初始化 dp 数组
没有障碍物时,我们将第一行和第一列的 dp[i][j] 都初始化为 1,因为一步走到底都只有一种路径,而当有了障碍物时,题目没有限制障碍物的位置,因此障碍物可以是在任意一个格子,因为我们需要初始化的是第一行和第一列,那么初始化时只需要看第一行及第一列是否有障碍物,有障碍物怎么处理?
当遇到了障碍物,遇到障碍物之前的格子的不同路径数就是 1 (因为只能沿直线走),遇到障碍物时,障碍物以及障碍物后面的格子的不同路径数都是 0,毕竟都被挡住了,机器人不可能到达。因此 dp 初始化如下:
//初始化dp数组
for(int i = 0; i < n; i++){
if(obstacleGrid[0][i] == 1) break;
dp[0][i] = 1;
}
for(int i = 0; i < m; i++) {
if(obstacleGrid[i][0] == 1) break;
dp[i][0] = 1;
}
确定遍历顺序
依旧看递推公式 :dp[i][j] = dp[i - 1][j] + dp[i][j - 1] ,求 dp[i][j] 需要已知左边以及上面格子的 dp[i][j],故而遍历顺序是 从上到下、从左到右 。
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];
}
}
举例推导 dp 数组

代码实现
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if(obstacleGrid[0][0] == 1)return 0;
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
//初始化dp数组
for(int i = 0; i < n; i++){
if(obstacleGrid[0][i] == 1) break;
dp[0][i] = 1;
}
for(int i = 0; i < m; i++) {
if(obstacleGrid[i][0] == 1) break;
dp[i][0] = 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];
}
}
《代码随想录》刷题记
本文详细解析了在存在障碍物的情况下,寻找从网格左上角到右下角的不同路径数量的问题。采用动态规划方法,通过初始化dp数组并定义递推公式,解决了机器人行走路径计算难题。

1016

被折叠的 条评论
为什么被折叠?



