本文将探讨“不同路径 II”这一问题,定义了在一个有障碍物的网格中,从起点到终点的路径数计算方法。我们将从基本概念入手,逐步深入理解问题的递推关系、动态规划的解决方案及其优化方法。通过详细的解释和代码示例,我们希望能帮助读者更好地掌握动态规划的思想与应用,提升解决复杂问题的能力。

给定一个
的网格,其中有一些障碍物。机器人从左上角(起始点)出发,只能向下或向右移动,目标是到达右下角(终点)。问总共有多少条不同的路径可以到达终点,路径上不得经过障碍物。
表示到达位置
的不同路径数,则:
;
。
,若位置是障碍物则设为
。
的二维数组 dp。
(遇到障碍物时设为
)。
,考虑障碍物的情况。
。
以上就是不同路径II 问题的基本思路。
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: list[list[int]]) -> int:
if not obstacleGrid or not obstacleGrid[0]:
return 0
rows, cols = len(obstacleGrid), len(obstacleGrid[0])
# 创建 dp 数组
dp = [[0] * cols for _ in range(rows)]
# 初始化第一行
for j in range(cols):
if obstacleGrid[0][j] == 1:
break # 遇到障碍物,后续路径数为0
dp[0][j] = 1
# 初始化第一列
for i in range(rows):
if obstacleGrid[i][0] == 1:
break # 遇到障碍物,后续路径数为0
dp[i][0] = 1
# 填充 dp 数组
for i in range(1, rows):
for j in range(1, cols):
if obstacleGrid[i][j] == 1:
dp[i][j] = 0 # 障碍物
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[rows-1][cols-1]在 Python 实现中,我们创建了一个二维数组 dp 用于存储到达每个点的路径数。首先初始化第一行和第一列,如果遇到障碍物,则设置路径数为0。接着,使用双重循环填充 dp 数组,根据之前讨论的递推关系进行计算。最终,返回右下角的路径数,即 dp[rows-1][cols-1]。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if (obstacleGrid.empty() || obstacleGrid[0].empty()) return 0;
int rows = obstacleGrid.size();
int cols = obstacleGrid[0].size();
// 创建 dp 数组
vector<vector<int>> dp(rows, vector<int>(cols, 0));
// 初始化第一行
for (int j = 0; j < cols; ++j) {
if (obstacleGrid[0][j] == 1) break; // 遇到障碍物
dp[0][j] = 1;
}
// 初始化第一列
for (int i = 0; i < rows; ++i) {
if (obstacleGrid[i][0] == 1) break; // 遇到障碍物
dp[i][0] = 1;
}
// 填充 dp 数组
for (int i = 1; i < rows; ++i) {
for (int j = 1; j < cols; ++j) {
if (obstacleGrid[i][j] == 1) {
dp[i][j] = 0; // 障碍物
} else {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
return dp[rows-1][cols-1];
}
};C++ 实现采用了 STL 的 vector 来动态创建和存储二维数组。与 Python 类似,我们首先初始化第一行和第一列的路径数,然后在嵌套循环中使用递推关系填充 dp 数组。C++ 的语法相对严格,但通过合理的注释,读者可以清楚地理解每一步的逻辑。
动态规划方法为解决带障碍物的路径问题提供了清晰且高效的解决方案。通过对 Python 和 C++ 代码的实现,我们展示了如何利用动态规划思想来应对复杂问题。掌握这些技巧不仅能帮助我们解决类似的路径问题,也为理解更复杂的动态规划问题打下了坚实的基础。