动态规划解决网格路径问题的核心是定义dpi为从起点到(i,j)的路径数或最优值,无障碍时dpi=dpi−1+dpi,有障碍则置0,需正确初始化边界并按行优先顺序填表。

动态规划解决“不同路径”和“机器人走棋盘”类问题,核心是把每一步的路径数或最优值存下来,避免重复计算。这类题本质都是网格上的单向移动(通常只允许向右或向下),状态定义清晰、转移简单,特别适合用 DP。
状态定义要贴合问题目标
设 dp[i][j] 表示从起点(左上角)走到位置 (i, j) 的路径总数(或最小路径和、是否可达等,依题目而定)。这个定义直接对应“有多少种方式到达这里”,逻辑直观,也方便推导转移关系。
- 无障碍时:dp[i][j] = dp[i−1][j] + dp[i][j−1](只能从上方或左方来)
- 有障碍时:若 grid[i][j] 是障碍(比如值为 1),则 dp[i][j] = 0;否则仍按上式计算
- 求最小路径和时:dp[i][j] = grid[i][j] + min(dp[i−1][j], dp[i][j−1]),注意初始化边界
初始化必须处理好边界情况
第一行和第一列没有“上方”或“左方”,只能沿单一方向到达:
- 无障碍网格:第一行所有格子 dp[0][j] = 1,第一列所有格子 dp[i][0] = 1
- 有障碍时,一旦某处出现障碍,它之后同行/同列的位置 dp 值全为 0(因为路被堵死)
- 更稳妥的做法是加一行一列“虚拟边界”,设 dp[0][1] = 1(或 dp[1][0] = 1),其余虚拟格为 0,这样填表时无需单独判断边界,代码更简洁
填表顺序决定能否正确依赖子问题
由于每个 dp[i][j] 只依赖于上方和左方,所以必须按从上到下、从左到右的顺序遍历二维数组。任意颠倒顺序(比如先列后行)会导致依赖未计算的值,结果错误。
- 外层循环控制行号 i,内层控制列号 j
- 确保 dp[i−1][j] 和 dp[i][j−1] 在计算 dp[i][j] 前已算出
- 对 m×n 网格,时间复杂度固定为 O(mn),空间也可优化到 O(n)(滚动数组)
障碍物不是额外难点,而是条件分支
障碍物不改变 DP 结构,只增加一个判断:
- 遍历时先检查当前位置是否可通行(如 obstacleGrid[i][j] == 0)
- 不可通行 → dp[i][j] = 0
- 可通行 → 按正常转移公式计算
- 起点或终点是障碍?直接返回 0,无需继续计算











