【LeetCode】动态规划—63. 不同路径 II(附完整Python/C++代码)

news2024/11/16 23:39:04

动态规划—63. 不同路径 II

  • 前言
  • 题目描述
  • 基本思路
    • 1. 问题定义:
    • 2. 理解问题和递推关系:
    • 3. 解决方法:
      • 3.1 动态规划方法
      • 3.2 空间优化的动态规划
    • 4. 进一步优化:
    • 5. 小总结:
  • 代码实现
    • Python3代码实现
    • Python 代码解释
    • C++代码实现
    • C++ 代码解释
  • 总结:

前言

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

题目描述

在这里插入图片描述

基本思路

1. 问题定义:

给定一个 m ∗ n m * n mn 的网格,其中有一些障碍物。机器人从左上角(起始点)出发,只能向下或向右移动,目标是到达右下角(终点)。问总共有多少条不同的路径可以到达终点,路径上不得经过障碍物。

2. 理解问题和递推关系:

  • 问题的本质是计算从起点到终点的所有可能路径数,但需要考虑障碍物的影响。
  • 关键观察:到达某个点的路径数等于到达其上方点的路径数加上到达其左方点的路径数,但若某个点是障碍物,则路径数为0。
  • 递推关系:设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示到达位置 ( i , j ) (i, j) (i,j) 的不同路径数,则:
    • 如果该位置是障碍物, d p [ i ] [ j ] = 0 dp[i][j] = 0 dp[i][j]=0
    • 否则, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] = dp[i-1][j] + dp[i][j-1] dp[i][j]=dp[i1][j]+dp[i][j1]
  • 边界条件:第一行和第一列的路径数初始化为 1 1 1,若位置是障碍物则设为 0 0 0

3. 解决方法:

3.1 动态规划方法

  1. 创建一个 m ∗ n m * n mn 的二维数组 dp。
  2. 初始化第一行和第一列的值为 1 1 1(遇到障碍物时设为 0 0 0)。
  3. 从左上到右下填充 dp 数组,使用递推公式: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] = dp[i-1][j] + dp[i][j-1] dp[i][j]=dp[i1][j]+dp[i][j1],考虑障碍物的情况。
  4. 最终结果为 d p [ m − 1 ] [ n − 1 ] dp[m-1][n-1] dp[m1][n1]

3.2 空间优化的动态规划

  1. 使用一维数组 dp 代替二维数组。
  2. 初始化 dp 数组的所有元素为0,第一列和第一行根据障碍物初始化。
  3. 逐行更新 dp 数组,每次更新时,当前值等于其自身(上一行的值)加上前一个元素(左边的值)。
  4. 最终结果为 dp[n-1]。

4. 进一步优化:

  • 尽管空间优化已减少了复杂度,仍然可以考虑:
    • 如果输入很大,可以采用更高效的数学模型或其他算法,但在此问题中,动态规划已较为高效。

5. 小总结:

  • 动态规划方法提供了直观且易于理解的解法,适用于理解路径问题的本质。
  • 空间优化的方法显著降低了空间复杂度,适用于处理大规模输入。
  • 这个问题是动态规划的经典案例,掌握它对于解决类似问题非常有帮助。理解障碍物的处理逻辑是动态规划中的重要技巧。

以上就是不同路径II 问题的基本思路。

代码实现

Python3代码实现

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 代码解释

在 Python 实现中,我们创建了一个二维数组 dp 用于存储到达每个点的路径数。首先初始化第一行和第一列,如果遇到障碍物,则设置路径数为0。接着,使用双重循环填充 dp 数组,根据之前讨论的递推关系进行计算。最终,返回右下角的路径数,即 dp[rows-1][cols-1]。

C++代码实现

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++ 代码解释

C++ 实现采用了 STL 的 vector 来动态创建和存储二维数组。与 Python 类似,我们首先初始化第一行和第一列的路径数,然后在嵌套循环中使用递推关系填充 dp 数组。C++ 的语法相对严格,但通过合理的注释,读者可以清楚地理解每一步的逻辑。


总结:

动态规划方法为解决带障碍物的路径问题提供了清晰且高效的解决方案。通过对 Python 和 C++ 代码的实现,我们展示了如何利用动态规划思想来应对复杂问题。掌握这些技巧不仅能帮助我们解决类似的路径问题,也为理解更复杂的动态规划问题打下了坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线性跟踪微分器TD详细测试(Simulink 算法框图+CODESYS ST+博途SCL完整源代码)

1、ADRC线性跟踪微分器 ADRC线性跟踪微分器(ST+SCL语言)_adrc算法在博途编程中scl语言-CSDN博客文章浏览阅读784次。本文介绍了ADRC线性跟踪微分器的算法和源代码,包括在SMART PLC和H5U平台上的实现。文章提供了ST和SCL语言的详细代码,并讨论了跟踪微分器在自动控制中的作用…

深入理解 Nuxt.js 中的 app:error 钩子

title: 深入理解 Nuxt.js 中的 app:error 钩子 date: 2024/9/27 updated: 2024/9/27 author: cmdragon excerpt: 摘要:本文深入讲解了Nuxt.js框架中的app:error钩子,介绍其在处理web应用中致命错误的重要作用、使用方法及实际应用场景。通过创建Nuxt项目、定义插件、触发…

基于nodejs+vue的水产品销售管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Could not find com.mapbox.mapboxsdk:mapbox-android-accounts:0.7.0.解决

AndroidStudio编译APK出现如下错误&#xff1a; Could not find com.mapbox.mapboxsdk:mapbox-android-accounts:0.7.0. 出现上面错误原因是因为没有打开对应的仓库导致的&#xff0c; 手动添加如下创建地址可解决&#xff1a; maven { url https://maven.aliyun.com/repos…

vue项目中的node、node-sass、sass-loader之间的版本关系

这个报错&#xff0c;想必大部分人都会遇到&#xff0c;版本不适配的问题&#xff0c;记录下解决方案。 版本适配问题 node 与node-sass node-sass与sass-loader sass-loader 4.1.1&#xff0c;node-sass 4.3.0sass-loader 7.0.3&#xff0c;node-sass 4.7.2sass-loader 7.3.…

dify新特性:并行agent/工作流开发与变量存储

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 再谈Agent&#xff1a;Dify智能体实现Txet2SQLMoe模式&#xff1a;或将是最好的大模…

UE5: Content browser工具编写

Extend content browser 创建自定义菜单入口的步骤&#xff1a;create custom menu entry. steps: Load content browser module -> PathViewContextMenuExtenders -> Add in our own delegate -> Bind to our own member functions 基础概念&#xff08;本文实…

C++【类和对象】(拷贝构造与运算符重载)

1. 拷贝构造 如果⼀个构造函数的第⼀个参数是自身类类型的引用&#xff0c;且任何额外的参数都有默认值&#xff0c;则此构造函数也叫做拷贝构造函数&#xff0c;也就是说拷贝构造是⼀个特殊的构造函数。 注意&#xff1a;拷贝构造是用一个已经实例化的对象来初始化一个新对象…

中级职称评审到底需要准备什么材料?

职称评审需要的材料非常非常多&#xff0c;其中涉及到各类表格&#xff0c;这些小资料&#xff0c;看起来简单&#xff0c;实则做起来复杂&#xff0c;不过这种资料只能当年通知出来之后进行整理&#xff0c;今天甘建二跟大家说一下职称评审中需要提前准备的一些重要材料&#…

5.10直方图均衡化

基本概念 直方图均衡化&#xff08;Histogram Equalization&#xff09;是一种常用的图像处理技术&#xff0c;用于改善图像的对比度。通过调整图像中像素值的分布&#xff0c;直方图均衡化可以使图像的动态范围更广&#xff0c;从而增强图像的细节可见度。 直方图均衡化原理…

c++ 杂项

简答题 1、什么是虚函数&#xff1f;什么是纯虚函数&#xff1f; 虚函数是在类中定义函数时&#xff0c;在函数前加 virtual 关键字。父子类中只有一个该函数。 如果子类中没有重写该虚函数。那么父子类空间中使用的都是父类定义的该函数。 如果子类中重写了该虚函数&#xff…

【Python基础(一)】

学习分享 一、基本语法1、输出print语句2、常量的写法3、运算符 (/) 与(//)4、字符串5、列表5.1、列表查询元素是否存在5.2、列表查询元素是否存在5.3、身份运算符5.4、列表的增删改查 6、元组6.1、tuple() 7、字典8、函数8.1、值传递8.2、引用传递8.3、函数的传参 二、文件的操…

小北的JDK1.8下载、安装和环境配置教程——附件资源

​前言 亲爱的友友们&#xff0c;欢迎来到小北博客&#xff01;今天&#xff0c;我们将一起探索如何下载、安装并配置JDK 1.8&#xff0c;这是Java开发中一个非常关键的步骤。无论你是Java新手还是资深开发者&#xff0c;掌握JDK的正确安装和配置都是必不可少的。Java Download…

828华为云征文 | 基于华为云Flexus云服务器X搭建部署——AI知识库问答系统(使用1panel面板安装)

&#x1f680;对于企业来讲为什么需要华为云Flexus X来搭建自己的知识库问答系统&#xff1f;&#xff1f;&#xff1f; 【重塑知识边界&#xff0c;华为云Flexus云服务器X引领开源问答新纪元&#xff01;】 &#x1f31f; 解锁知识新动力&#xff0c;华为云Flexus云服务器X携…

【工具分享】Jigsaw勒索病毒解密工具

前言 Jigsaw勒索软件首次出现在2016年&#xff0c;以其独特的威胁手段迅速在网络安全界引起广泛关注。该恶意软件因其在勒索信中使用了恐怖电影《电锯惊魂》中的角色Billy the Puppet的图像而得名。Jigsaw不仅会加密受害者的文件&#xff0c;还会逐渐删除这些文件以迫使受害者…

基于nodejs+vue的游戏陪玩系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

大数据毕业设计选题推荐-国潮男装微博评论数据分析系统-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

当大模型成为新一代操作系统,我们如何转型AI产品经理?

大模型无疑是最近科技圈最炙手可热的时尚单品&#xff0c;跟AIGC能沾上边的工作岗位都成为行业香饽饽。许多产品经理朋友与斯年讨论如何转型AI产品经理&#xff0c;今天想通过用户体验五要素的逻辑框架&#xff0c;谈谈传统型产品经理 VS. AI型产品经理的差异。最后分享几点在转…

教师工作量数字化管理平台

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…