LeetCode 第63题:不同路径 II

LeetCode 第63题:不同路径 II

题目描述

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

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

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

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

难度

中等

题目链接

点击在LeetCode中查看题目

示例

示例 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.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j]01

解题思路

动态规划

这是"不同路径"的变体,需要考虑障碍物的影响。我们仍然可以使用动态规划,但需要特别处理障碍物的情况。

关键点:

  1. 如果起点或终点有障碍物,直接返回0
  2. 遇到障碍物时,该位置的路径数为0
  3. 第一行和第一列的处理需要特别注意
  4. 可以复用输入数组来节省空间

具体步骤:

  1. 检查起点是否有障碍物
  2. 初始化第一行和第一列
  3. 动态规划计算每个位置的路径数
  4. 注意处理障碍物的特殊情况

图解思路

算法步骤分析表

步骤 操作 状态 说明
初始 检查 \[0,0,0,0,1,0,0,0,0] 原始网格
第1步 初始化 \[1,1,1,0,0,0,0,0,0] 处理第一行
第2步 计算 \[1,1,1,1,0,1,0,0,0] 处理第二行
最终 完成 \[1,1,1,1,0,1,1,1,2] 得到结果

状态/情况分析表

情况 输入 输出 说明
起点障碍 \[1,0] 0 无法开始
终点障碍 \[0,1] 0 无法到达
中间障碍 \[0,0,0,1] 0 被阻断

代码实现

C# 实现

csharp 复制代码
public class Solution {
    public int UniquePathsWithObstacles(int[][] obstacleGrid) {
        if (obstacleGrid == null || obstacleGrid.Length == 0) return 0;
        
        int m = obstacleGrid.Length;
        int n = obstacleGrid[0].Length;
        
        // 如果起点或终点有障碍,直接返回0
        if (obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) return 0;
        
        // 使用long避免整数溢出
        long[] dp = new long[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 (int)dp[n-1];
    }
}

Python 实现

python 复制代码
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        if not obstacleGrid or not obstacleGrid[0]:
            return 0
        
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        
        # 如果起点或终点有障碍,直接返回0
        if obstacleGrid[0][0] == 1 or obstacleGrid[m-1][n-1] == 1:
            return 0
        
        # 使用一维数组优化空间复杂度
        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]

C++ 实现

cpp 复制代码
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if (obstacleGrid.empty() || obstacleGrid[0].empty()) return 0;
        
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        
        // 如果起点或终点有障碍,直接返回0
        if (obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) return 0;
        
        // 使用long避免整数溢出
        vector<long> 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];
    }
};

执行结果

  • 执行用时:80 ms
  • 内存消耗:37.5 MB

代码亮点

  1. 🎯 使用一维数组优化空间复杂度
  2. 💡 使用long类型避免溢出
  3. 🔍 巧妙处理障碍物情况
  4. 🎨 代码结构清晰简洁

常见错误分析

  1. 🚫 没有检查起点和终点的障碍物
  2. 🚫 整数溢出问题
  3. 🚫 边界条件处理不当
  4. 🚫 障碍物处理逻辑错误

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
DFS递归 O(2^(m+n)) O(m+n) 直观易懂 超时
二维DP O(mn) O(mn) 容易理解 空间消耗大
一维DP O(mn) O(n) 最优解法 不够直观
原地修改 O(mn) O(1) 空间最优 修改输入

相关题目

相关推荐
handler0116 分钟前
【算法】并查集(普通/扩展/带权)模板与例题
数据结构·c++·笔记·算法·c·图论·查并集
kcuwu.30 分钟前
Claw Code 项目架构万字解读
人工智能·架构
qq74223498432 分钟前
从“感知”到“决断”:测评百度伐谋产业决策智能体的端到端推理与行动机制
人工智能·算法·百度·大模型·运筹优化
Rain5091 小时前
mini-cc 终端 UI:用 React 写 CLI 是什么体验
前端·人工智能·react.js·ui·架构·前端框架·ai编程
愚公搬代码1 小时前
【愚公系列】《移动端AI应用开发》014-DeepSeek API开发与集成(处理多轮对话与动态请求)
人工智能·中间件·架构
2603_954708311 小时前
微电网协调控制系统柜的应用场景有哪些?
分布式·安全·架构·能源·需求分析
huohaiyu1 小时前
深入解析Java垃圾回收机制
java·开发语言·算法·gc
LONGZETECH1 小时前
汽车仿真教学软件技术实现深度解析:从三维建模到学情数据闭环
c语言·3d·unity·架构·汽车
浮芷.1 小时前
鸿蒙PC端 TTS 并发调用问题详解:资源竞争与队列管理
算法·华为·开源·harmonyos·鸿蒙·鸿蒙系统
AI科技星2 小时前
精细结构常数α的多维度物理比值特性及空间螺旋模型研究
人工智能·线性代数·架构·概率论·学习方法