动态规划解决LeetCode 63题:不同路径 II(含障碍物)
1. 题目链接
LeetCode 63. 不同路径 II
2. 题目描述
一个机器人位于 m x n
网格的左上角,每次只能向右或向下移动一步。网格中可能存在障碍物(标记为 1
),机器人不能经过障碍物。求从左上角到右下角的不同路径总数。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:存在障碍物在中心位置,两条路径为:
- 右 -> 右 -> 下 -> 下
- 下 -> 下 -> 右 -> 右
示例 2:
输入:obstacleGrid = [[0,1],[0,0]]
输出:1
3. 示例分析
以 示例 1 的输入为例:
- 机器人需要绕过中心的障碍物。
- 动态规划表
dp
在计算时会跳过障碍物位置,最终右下角的值为2
。
4. 算法思路
动态规划状态定义
dp[i][j]
表示到达网格(i-1, j-1)
位置的有效路径数(i
和j
从1
开始,避免越界)。
状态转移方程
- 若
(i-1, j-1)
是障碍物,dp[i][j] = 0
(无法到达)。 - 否则,
dp[i][j] = dp[i-1][j] + dp[i][j-1]
。
初始化技巧
- 初始化
dp[0][1] = 1
,使得dp[1][1]
可以正确推导初始值,无需单独处理第一行和第一列。
5. 边界条件与注意事项
- 起点或终点为障碍物:直接返回
0
。 - 单行或单列网格:若路径中存在障碍物,路径数为
0
。 - 障碍物处理:遍历时需跳过障碍物位置,保持
dp[i][j] = 0
。
6. 代码实现(修正版)
class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m = obstacleGrid.size(), n = obstacleGrid[0].size();// 起点或终点是障碍物,直接返回0if (obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) return 0;vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));dp[0][1] = 1; // 初始化虚拟起点for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {// 跳过障碍物位置if (obstacleGrid[i-1][j-1] == 0) {dp[i][j] = dp[i-1][j] + dp[i][j-1];}}}return dp[m][n];}
};
代码解析
- 提前检查障碍物:若起点或终点是障碍物,直接返回
0
,避免无效计算。 - 动态规划表填充:遍历时跳过障碍物位置,保证路径数不会累加无效值。
- 返回值:
dp[m][n]
表示到达右下角的有效路径总数。
时间复杂度:O(mn)
,空间复杂度:O(mn)
。通过动态规划表逐格计算,高效处理含障碍物的路径问题。