题目

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 10 来表示。

示例 1:

img

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

示例 2:

img

输入:obstacleGrid = [[0,1],[0,0]]
输出:1

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j]01

解答

  • 动态规划

这是一道典型的动态规划问题。定义一个二维数组dp,其中dp[i][j]表示从左上角出发到第i行第j列的格子的不同路径数目。

在定义dp数组时,需要特别注意:如果某个格子为障碍物,则不能通过该格子,路径数为0;如果第一列某个格子为障碍物,则其下方的所有格子均无法到达,路径数为0;如果第一行某个格子为障碍物,则其右方的所有格子均无法到达,路径数为0。

在状态转移方程中,如果某个格子为障碍物,则其路径数为0;否则,其到达的路径有两种:从上方的格子到达和从左边的格子到达。因此,其不同路径数目为到达其上方格子的路径数目加上到达其左边格子的路径数目之和,即:

dp[i][j] = dp[i-1][j] + dp[i][j-1]

最终答案为dp[m-1][n-1],即到达右下角的不同路径数目。

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        // 定义二维数组dp
        vector<vector<int>> dp(m, vector<int>(n, 0));
        // 初始化第一列
        for (int i = 0; i < m; i++) {
            if (obstacleGrid[i][0] == 1) {
                break;
            }
            dp[i][0] = 1;
        }
        // 初始化第一行
        for (int j = 0; j < n; j++) {
            if (obstacleGrid[0][j] == 1) {
                break;
            }
            dp[0][j] = 1;
        }
        // 对于其他格子,其不同路径数目为到达其上方格子的路径数目加上到达其左边格子的路径数目之和
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (obstacleGrid[i][j] == 1) {  // 如果当前格子为障碍物,则不可到达,路径数为0
                    dp[i][j] = 0;
                } else {  // 否则,其到达的路径有两种:从上方的格子到达和从左边的格子到达
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        // 返回右下角格子的不同路径数目
        return dp[m-1][n-1];
    }
};