问题描述
一个机器人位于一个 m x n 网格的左上角 (起始点在标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1
和 0
来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
Java 实现
方法一:递归实现
递归实现实际上就是一个动态规划的思想。假设机器人此时正处于位置 (i, j),由于机器人只能向右或者向下走一步,因此在当前位置可以到达终点的路径数,就是向下一步后能到达终点的路径数,与向右一步后能到达终点的路径数,即 dp[i][j] = dp[i+1][j+1]。计算时需要考虑边界条件,而且如果机器人到达了终点,则返回 1 以表示到达此点可算作一个有效路径。
但是,从代码中可以看出,我们每走一步都需要调用一次递归函数,最坏情况可能会调用 m × n 次。
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid[0][0] == 0) {
return numOfPath(obstacleGrid, 0, 0);
} else {
return 0;
}
}
public int numOfPath(int[][] grid, int i, int j) {
int m = grid.length, n = grid[0].length;
// Reach the destination.
if (i == m - 1 && j == n - 1) {
return 1;
}
int cntPath = 0;
// Go down.
if (i + 1 < m && grid[i + 1][j] == 0) {
cntPath += numOfPath(grid, i + 1, j);
}
// Go right.
if (j + 1 < n && grid[i][j + 1] == 0) {
cntPath += numOfPath(grid, i, j + 1);
}
return cntPath;
}
}
方法二:动态规划。
思路跟方法一类似,但我们反过来从终点开始计算,构建 dp[][] 矩阵,最后取位置 (0, 0) 的值即为所求。由于当机器人在边缘的时候,它必然只能往一个方向进行下一个。所以,我们可以首先把边缘值计算出来,再把矩阵内部其他值依次填充。
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length, n = obstacleGrid[0].length;
// Obestacle locates on the start or the destination.
if (obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) {
return 0;
}
int[][] dp = new int[m][n];
// Intialize the number of paths at the edges.
dp[m-1][n-1] = 1;
// The last column.
for (int i = m - 2; i >= 0; --i) {
if (obstacleGrid[i][n-1] == 0) {
dp[i][n-1] = dp[i+1][n-1];
} else {
dp[i][n-1] = 0;
} // if
} // for
// The last row.
for (int j = n - 2; j >= 0; --j) {
if (obstacleGrid[m-1][j] == 0) {
dp[m-1][j] = dp[m-1][j+1];
} else {
dp[m-1][j] = 0;
} // if
} // for
for (int i = m - 2; i >= 0; --i) {
for (int j = n - 2; j >= 0; --j) {
if (obstacleGrid[i][j] == 0) {
dp[i][j] = dp[i+1][j] + dp[i][j+1];
} else {
dp[i][j] = 0;
} // if
} // for
} // for
return dp[0][0];
}
}