問題描述
一個機器人位於一個 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];
}
}