63. 不同路徑 II
一個機器人位於一個 m x n
網格的左上角 (起始點在下圖中標記為 “Start” )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為 “Finish”)。
現在考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不同的路徑?
網格中的障礙物和空位置分別用 1
和 0
來表示。
【思路】
動規五部曲:
1、確定dp陣列以及下標的含義
dp[i][j]:表示從(0,0)出發,到(i,j)有dp[i][j]條不同的路徑。
2、確定遞推公式
遞推公式和上面那題一樣,dp[i][j] = dp[i-1][j]+dp[i][j-1]。
但這裡需要注意的是,因為有了障礙的話應該就保持初始狀態(初始狀態為0)。
if (obstacleGrid[i][j] == 0) {//當(i, j)沒有障礙的時候,再推導dp[i][j]
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
3、dp陣列如何初始化
int[][] dp = new int[m][n];
for(int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for(int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
因為從(0,0)的位置到(i,0)的路徑只有一條,所以dp[i][0]一定為1,dp[0][j]也同理。
但如果(i, 0)這條邊有了障礙之後,障礙之後(包括障礙)都是走不到的位置了,所以障礙之後的dp[i][0]應該還是初始值0。
注意程式碼裡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]一定有數值。
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];
}
}
5、舉例推導dp陣列
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
//如果在起點或終點出現了障礙,直接返回0
if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) {
return 0;
}
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) {
dp[i][0] = 1;
}
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) {
dp[0][j] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = (obstacleGrid[i][j] == 0) ? dp[i - 1][j] + dp[i][j - 1] : 0;
}
}
return dp[m - 1][n - 1];
}
}