不同路径 II
力扣:63. 不同路径 II - 力扣(LeetCode)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
- 向右 -> 向右 -> 向下 -> 向下
- 向下 -> 向下 -> 向右 -> 向右
示例 2:
输入:obstacleGrid = [[0,1],[0,0]]
输出:1
提示:
m == obstacleGrid.length
n == obstacleGrid[i].length
1 <= m, n <= 100
obstacleGrid[i][j] 为 0 或 1
这道题相对于上一篇文章中不同路径 就是有了障碍。第⼀次接触这种题⽬的同学可能会有点懵,这有障碍了,应该怎么算呢?不同路径中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp数组[i][j]保持初始值(0)就可以了。
动规五部曲:
1. 确定dp数组以及下标的含义
和上一篇文章一样因为机器⼈从(0 , 0) 位置触发,到(m - 1, n - 1)终点。所以定义二维数组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] == 1就是障碍的应该就保持初始状态(初始状态为0)。
所以Java代码为:
if(obstacleGrid[i][j] == 0){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
3. dp数组如何初始化
在上一篇文章不同路径中我们给出如下的初始化:
int[][] dp = new int[m][n]; //初始化都为0
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
因为从(0, 0)的位置到(i, 0)的路径只有⼀条,所以dp[i][0]⼀定为1,dp[0][j]也同理。但如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是⾛不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0。
如图:
所以本题代码初始化为:
for(int i = 0; i < x && obstacleGrid[i][0] == 0; i++){
dp[i][0] = 1;
}
for(int i = 0; i < y && obstacleGrid[0][i] == 0; i++){;
dp[0][i] = 1;
}
注意代码⾥for循环的终⽌条件,⼀旦遇到obstacleGrid[i][0] == 1的情况就停⽌dp[i][0]的赋值1的操 作,dp[0][j]同理。
4. 确定遍历顺序
从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,⼀定是从左到右⼀层⼀层遍历,这样保证推导 dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]⼀定是有数值。
5. 举例推导dp数组
用图一推导:
如果这个图看不懂,建议在理解⼀下递归公式,然后照着⽂章中说的遍历顺序,⾃⼰推导⼀下!
动规五部分分析完毕,对应Java代码如下:
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int x = obstacleGrid.length;
int y = obstacleGrid[0].length;
int[][] dp = new int[x][y];
for(int i = 0; i < x && obstacleGrid[i][0] == 0; i++)
dp[i][0] = 1;
for(int i = 0; i < y && obstacleGrid[0][i] == 0; i++)
dp[0][i] = 1;
for(int i = 1; i < x; i++){
for(int j = 1; j < y; j++){
if(obstacleGrid[i][j] == 0)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
else
continue;
}
}
return dp[x - 1][y - 1];
}
}
本题是62.不同路径的障碍版,整体思路⼤体⼀致。但就算是做过62.不同路径,在做本题也会有感觉遇到障碍⽆从下⼿。其实只要考虑到,遇到障碍dp[i][j]保持0就可以了。也有⼀些⼩细节,例如:初始化的部分,很容易忽略了障碍之后应该都是0的情况。