leetcode63. 不同路径 II(动态规划-java)

news2024/11/9 0:11:39

不同路径 II

  • leetcode63. 不同路径 II
    • 题目描述
    • 暴力递归
    • 代码演示
    • 动态规划
      • 代码演示
    • 动态规划空间压缩
  • 动态规划专题

leetcode63. 不同路径 II

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/unique-paths-ii

题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。

示例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] 为 0 或 1

暴力递归

这题是leetcode62. 不同路径 的拓展版.加了障碍物,解题思路是一样的,只是要加下障碍物的判断.
还是向下和向右两个方向的选择,两种情况的和就是所有的路线数.

代码演示

/**
* 主方法
*/
 public int uniquePathsWithObstacles(int[][] obstacleGrid) {
 	//如果右下角是障碍物,怎么都过不去,直接返回0
        if(obstacleGrid[obstacleGrid.length - 1][obstacleGrid[0].length - 1] == 1){
            return 0;
        }
        //开始递归
        return process(obstacleGrid,0,0);
    }
	/**
	* 暴力递归
	* i 和 j 描述当前在的位置
	*/
    public int process(int[][]obstacleGrid,int i,int j){
    	//base case 来到最后一个位置,前面路线有效,返回1
        if(i == obstacleGrid.length - 1 && j == obstacleGrid[0].length - 1 ){
            return 1;
        }
        //越界,路线无效 返回0
        if(i >= obstacleGrid.length || j >= obstacleGrid[0].length){
            return 0;
        }
        // 碰到障碍物,无效返回0
        if(obstacleGrid[i][j] == 1){
            return 0;
        }
        //x向下和向右两种情况
        int down = process(obstacleGrid,i + 1,j);
        int right = process(obstacleGrid,i,j + 1);
        //两种情况累加就是所有的路线
        return down + right;
    }

动态规划

从暴力递归中可以得知,(i,j) 位置依赖 (i+1,j)和(i,j+1)两个位置,所以可以轻松得到状态转移方程是:

f(i,j) = f(i+1,j) + f(i,j+1;
但这里有一些需要注意的地方,就是障碍物的处理,和dp表的初始化,我们以图为例:
在这里插入图片描述
上面图代表要走的网格,我只填写了最后一行和一列其他位置没有标注,因为现在只讨论最后一行和一列的情况.
最后一行为例,三角符号标注的位置是最后一次出现的障碍物,在这个障碍物之前的最后一行位置,都无法到最后位置了,所以之前的位置在dp 表中要初始化为0,之后的可以初始化为1,
最后一列也是同样情况:
下面看下代码中如何处理;

代码演示

  /**
     * 动态规划
     * @param obstacleGrid
     * @return
     */
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int n = obstacleGrid.length;
        int m = obstacleGrid[0].length;
        //最有下角如果是障碍物,就无法过去,返回 0
        if (obstacleGrid[n - 1][m - 1] == 1) {
            return 0;
        }
        //动态规划表
        int[][]dp = new int[n][m];
        //来标记最后一行最后一次出现障碍物的位置
        int flagN = -1;
        //来标记最后一列最后一次出现障碍物的位置
        int flagM = -1;
        for (int i = m - 1; i >= 0;i--){
            if(obstacleGrid[n - 1][i] == 1){
                flagN = i;
                break;
            }
        }
        //最后一个障碍物之后的位置初始化为1
        for (int i = flagN + 1; i < m;i++){
            dp[n - 1][i] = 1;
        }
        //标记最后一列最后一次出现障碍物的位置.
        for (int j =  n - 1; j >= 0;j--){
            if(obstacleGrid[j][m - 1] == 1){
                flagM = j;
                break;
            }
        }
        //最后一个障碍物之后的位置初始化为1
        for (int j = flagM + 1; j < n;j++){
            dp[j][m - 1] = 1;
        }

        for (int i = n - 2;i >= 0;i--){
            for (int j = m - 2;j >= 0;j--){
                //当前位置本身是障碍物 即为0
                if(obstacleGrid[i][j] == 1){
                    dp[i][j] = 0;
                }else{
                    //z状态转移方程
                    dp[i][j] = dp[i + 1][j] + dp[i][j + 1];
                }

            }
        }
        return dp[0][0];
    }

动态规划空间压缩

  /**
     * 动态规划 + 空间压缩
     * @param obstacleGrid
     * @return
     */
    public int uniquePathsWithObstacles2(int[][] obstacleGrid) {
        int n = obstacleGrid.length;
        int m = obstacleGrid[0].length;
        if (obstacleGrid[n - 1][m - 1] == 1) {
            return 0;
        }
        int[]dp = new int[m];
        int flagN = -1;
        for (int i = m - 1; i >= 0;i--){
            if(obstacleGrid[n - 1][i] == 1){
                flagN = i;
                break;
            }
        }
        for (int i = flagN + 1; i < m;i++){
            dp[i] = 1;
        }
        int flagM = -1;
        for (int j =  n - 1; j >= 0;j--){
            if(obstacleGrid[j][m - 1] == 1){
                flagM = j;
                break;
            }
        }

        for (int i = n - 2;i >= 0;i--){
            dp[m - 1] = i > flagM ? 1 : 0;
            for (int j = m - 2;j >= 0;j--){
                if(obstacleGrid[i][j] == 1){
                    dp[j] = 0;
                }else{
                    dp[j] = dp[j] + dp[j + 1];
                }

            }
        }
        return dp[0];
    }

动态规划专题

leetcode62. 不同路径

leetcode877. 石子游戏

leetcode64. 最小路径和

leetcode416. 分割等和子集

leetcode354. 俄罗斯套娃信封问题

leetcode300. 最长递增子序列

leetcode337. 打家劫舍 III

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

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

相关文章

自然图像中的字符识别:Chars74K 数据集

字符识别是 研究人员从计算机早期开始工作 视觉。随着当今相机的无所不在&#xff0c;应用 的自动字符识别比以往任何时候都更广泛。为 拉丁字母&#xff0c;这在很大程度上被认为是一个已解决的问题 受限情况&#xff0c;例如扫描文档的图像 包含常用字符字体和统一 背景。但是…

7.4_3B+树

特点&#xff1a;块内无序&#xff0c;块间有序(类比于分块查找) 这个性质是为了追求平衡 3&#xff09;结点的子树个数与关键字个数相等 4&#xff09;所有叶节点包含全部关键字及指向相应记录的指针&#xff0c;叶节点中将关键字按照大小顺序排列&#xff0c; 并且相邻叶节点…

Camera之android8.0以上HIDL与C++数据类型转换(三十)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

rust 集合、错误处理、泛型、Trait、生命周期、包

集合组织特性相同的数据&#xff1b;泛型可以定义任何抽象数据类型&#xff1b;生命周期限制所有权的作用域范围&#xff1b;错误处理使程序更健壮。 集合 一组特性相同的数据集合&#xff0c;除了基本数据类型的元组、数组。rust 标准库提供了一些非常有用的数据结构。 Vec…

Redis从入门到精通【进阶篇】之高可用主从详解

文章目录 0.前言1.详解1.1 主从复制概述1.2 主从复制原理1.2.1.全量复制1.2.2.增量复制1.2.3.详细描述1.3 更深入理解1.4 常见面试题 2. 总结3. Redis从入门到精通系列文章 0.前言 Redis是一个高性能的键值存储系统&#xff0c;广泛应用于Web应用、缓存、消息队列等领域。在实…

C++【STL】之priority_queue学习

优先级队列 优先级队列priority_queue也是STL库中容器适配器的一种&#xff0c;常用于进行数据优先级的处理&#xff0c;说到这儿是不是发现有些熟悉&#xff0c;没错它和我们之前讲解的堆本质上就是一个东西&#xff0c;底层都是数组存储的完全二叉树&#xff0c;它在STL库中…

零基础速成simulink代码生成——DBC文件CAN报文+stateflow 5

零基础速成simulink代码生成——DBC文件CAN报文+stateflow 5 上一篇文章中,已经实现将dbc文件进行代码生成,这边我们要实现一个功能,添加多几个can报文分时发送,结合statflow简单实现这个功能。 添加报文 我们还是选用相同的can报文添加 选中所有的模块,ctrl+c。 ctrl+…

InvPT++:用于视觉场景理解的倒金字塔多任务Transformer

文章目录 InvPT: Inverted Pyramid Multi-Task Transformer for Visual Scene Understanding摘要本文方法整体结构InvPT EncoderTask-Specific Preliminary DecodersStructure of InvPT DecodeUP-Transformer BlockCross-Scale Self-Attention: Fusion Attention and Selective…

团体程序设计天梯赛-练习集L1篇⑦

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的普通人。 &#x1f3c0;个人主页&#xff1a;陈童学哦CSDN &#x1f4a1;所属专栏&#xff1a;PTA &#x1f381;希望各…

ChatGPT | LangChain的文本切割方法对比

本文来自http://blog.csdn.net/hellogv/ &#xff0c;引用必须注明出处&#xff01; ChatGPT面向对话格式的文本理解很好&#xff0c;但如果要把网络上的文章让ChatGPT直接分析则会有格式的问题。文本清洗是个大课题&#xff0c;讲起来需要很多篇幅&#xff0c;优化起来前路漫…

学习C++的意义

文章目录 前言意义软件方法论的发展面向对象的程序设计宽泛的意义 C到C的升级ubuntu安装g编译器总结 前言 C是一种强大而广泛应用的编程语言&#xff0c;具有广泛的用途和应用领域。无论你是计算机科学专业的学生、自学编程的爱好者&#xff0c;还是想要进一步提升编程技能的专…

在linux系统中如何设置定时任务

前言&#xff1a; 在linux日常运维过程中我们常常需要在指定时间段自动停止或启动某个服务我们不可能人为的手动去执行&#xff0c;这时候我们就可以给对应的任务设置一个定时。后面我就可以将周期性的、规则的工作交给定时任务去完成。 **一次性任务&#xff1a;**顾名思义就是…

SAP CAP篇七:为CAP添加Fiori Launchpad入口 (Sandbox环境)

本文目录 本系列之前的文章在现有代码基础上继续增强增强app文件夹文件 package.json文件夹appconfig文件fioriSandboxConfig.json文件 fiori.html更新Srv中的UiIndexContentProviderFactory 再次检查代码运行效果代码库 (Gitcode) 本系列之前的文章 本系列之前的文章&#xf…

javaWeb之cookiesession

1 回顾 1.1 response对象 一次响应封装对象&#xff0c;由服务器创建。使用response对象将服务器需要的数据发送给浏览器。 将数据存放response对象中&#xff0c;tomcat从response对象获得数据&#xff0c;根据数据组织http响应&#xff0c;最后将http响应内容发送给浏览器&…

CTF-Show密码学:ZIP文件密码破解【暴力破解】

萌新 隐写23 题目内容&#xff1a; 文件的主人喜欢用生日做密码&#xff0c;而且还是个90后。 一、已知条件 在这个题目中&#xff0c;我们有以下已知条件&#xff1a; 文件的主人喜欢用生日做密码 - 这个条件告诉我们&#xff0c;密码可能是一个八位的纯数字密码&#xff0c…

windows服务器——部署PKI与证书服务

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 学习导图 一.PKI 概念 1.PKI体系能够实现的功能 二.公钥加密技术 1.公钥加…

股票量化系统QTYX选股框架实战案例集|大盘跳水,上涨趋势票抗跌-230621

前言 “实战案例个股画像”系列是和大家分享我基于QTYX的选股框架&#xff0c;在实战中选股的应用案例&#xff0c;和大家一起见证QTYX选股框架逐步完善的过程&#xff0c;帮助大家更好地理解QTYX选股框架精髓。 关于QTYX的使用攻略可以查看链接&#xff1a;QTYX使用攻略 首先要…

C++ 面向对象(2)——继承

C 继承 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。这样做&#xff0c;也达到了重用代码功能和提高执行效率的效果。 当创建一个类时&#xff0c;您不需要重新编写新的数据成员和…

【Python】异常处理 ① ( 异常概念 | 异常处理 | 异常捕获 )

文章目录 一、Python 异常简介1、异常概念2、Python 异常示例 二、Python 异常处理1、异常处理简介2、代码实例 - 出现异常代码3、代码实例 - 出现异常并进行捕获处理 一、Python 异常简介 1、异常概念 Python 异常 是在程序运行过程中发生的错误或问题的表示 ; 出现异常可能会…

【软件设计师暴击考点】面向对象考点暴击系列

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;软件…