Medium
题目描述
给你一个 m x n 的整数数组 grid。一个机器人初始位于左上角(即 grid[0][0])。机器人尝试移动到右下角(即 grid[m - 1][n - 1])。机器人每次只能向下或者向右移动一步。
网格中的障碍物和空位置分别用 1 和 0 来表示。机器人的移动路径不能包含任何有障碍物的方格。
返回机器人能够到达右下角的不同路径数量。
测试用例保证答案小于等于 2 * 10^9。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
示例 2:
输入:obstacleGrid = [[0,1],[0,0]]
输出:1
提示:
m == obstacleGrid.lengthn == obstacleGrid[i].length1 <= m, n <= 100obstacleGrid[i][j]为0或1
解题思路
这是一道经典的动态规划问题,是"不同路径"问题的变种,增加了障碍物的限制。
核心思路:
状态定义:
dp[i][j]表示从起点(0,0)到达位置(i,j)的不同路径数量。状态转移:
- 如果
obstacleGrid[i][j] == 1(有障碍物),则dp[i][j] = 0 - 如果
obstacleGrid[i][j] == 0(无障碍物),则dp[i][j] = dp[i-1][j] + dp[i][j-1]
- 如果
边界处理:
- 如果起点就有障碍物,直接返回 0
- 第一行和第一列需要特殊处理,因为只能从一个方向到达
优化方案:
- 方案一:使用二维 DP 数组,空间复杂度 O(mn)
- 方案二:使用一维 DP 数组,空间复杂度 O(n)(推荐)
- 方案三:原地修改输入数组(如果允许的话)
算法步骤:
- 检查起点是否有障碍物
- 初始化 DP 数组
- 按行遍历,根据状态转移方程更新 DP 值
- 返回右下角的路径数
代码实现
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
// 如果起点或终点有障碍物,直接返回0
if (obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) {
return 0;
}
// 使用一维DP数组优化空间复杂度
vector<int> dp(n, 0);
dp[0] = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (obstacleGrid[i][j] == 1) {
dp[j] = 0;
} else if (j > 0) {
dp[j] += dp[j-1];
}
}
}
return dp[n-1];
}
};
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m, n = len(obstacleGrid), len(obstacleGrid[0])
# 如果起点或终点有障碍物,直接返回0
if obstacleGrid[0][0] == 1 or obstacleGrid[m-1][n-1] == 1:
return 0
# 使用一维DP数组优化空间复杂度
dp = [0] * n
dp[0] = 1
for i in range(m):
for j in range(n):
if obstacleGrid[i][j] == 1:
dp[j] = 0
elif j > 0:
dp[j] += dp[j-1]
return dp[n-1]
public class Solution {
public int UniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.Length;
int n = obstacleGrid[0].Length;
// 如果起点或终点有障碍物,直接返回0
if (obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) {
return 0;
}
// 使用一维DP数组优化空间复杂度
int[] dp = new int[n];
dp[0] = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (obstacleGrid[i][j] == 1) {
dp[j] = 0;
} else if (j > 0) {
dp[j] += dp[j-1];
}
}
}
return dp[n-1];
}
}
/**
* @param {number[][]} obstacleGrid
* @return {number}
*/
var uniquePathsWithObstacles = function(obstacleGrid) {
const m = obstacleGrid.length;
const n = obstacleGrid[0].length;
// 如果起点或终点有障碍物,直接返回0
if (obstacleGrid[0][0]
复杂度分析
| 复杂度类型 | 二维DP | 一维DP(推荐) |
|---|---|---|
| 时间复杂度 | O(mn) | O(mn) |
| 空间复杂度 | O(mn) | O(n) |
其中 m 为网格的行数,n 为网格的列数。一维DP优化方案在保持相同时间复杂度的情况下,将空间复杂度从 O(mn) 优化到 O(n)。
相关题目
. Unique Paths (Medium)
. Unique Paths III (Hard)
. Minimum Path Cost in a Grid (Medium)