05_不同路徑2(帶障礙物版)

鲍宪立發表於2024-05-25

63. 不同路徑 II

一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記為 “Start” )。

機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為 “Finish”)。

現在考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不同的路徑?

網格中的障礙物和空位置分別用 10 來表示。

image-20240525102817297

【思路】

動規五部曲:

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];
    }
}

相關文章