算法【Java】—— 动态规划之路径问题

news2024/11/24 11:50:43

前言

本文章终点解析第一道题目【不同路径】和最后一道题目【地下城游戏】的动态规划思路,中间几道题目会很快过完,大家如果不熟悉动态规划的思路可以重点看一下这两道题目的解析。

不同路径

https://leetcode.cn/problems/unique-paths

在这里插入图片描述


解析:
首先确定状态表示:根据经验和题目要求,我们将 dp[i][j] 表示为达到 i j 位置一共有多少条路径。

接着推导状态转移方程:首先要到达 i, j 位置一共有两种方式,要么从 i-1,j 向下达到,要么从 i, j-1 向右达到。
我们将达到 i-1, j 和 达到 i , j-1 一共有多少条路径进行相加就可以得到 到达 i, j 位置 一共有多少种方式了。那么如何获得 达到 i-1, j 和 达到 i , j-1 一共有多少条路径?这不就是我们的状态表示吗,即 dp[i-1][j] 和 dp[i][j-1]
所以状态转移方程为 dp[i][j] = dp[i-1][j] + dp[i][j-1]
在这里插入图片描述

现在来进行初始化,为了方便我们填表不发生越界,我们决定多开一列和一行:
在这里插入图片描述
蓝色区域是我们要多开的空间,为什么开的是左边和上面的空间,因为我们的状态转移方程要用到上面和做左边的状态数值,为了避免在求原数组第一行和第一列发生越界,我们就多开了这部分空间,如果你不开,你就要在填表之前把第一行和第一列给提前填好。

初始化还要注意填表的正确性,因为我们多开的空间是会影响到第一行和第一列的状态数值的,我们必须保证第一行和第一列是正确的状态数值。
在这里插入图片描述
第一个状态数值应该为多少?状态表示是到达某个位置一共有多少条路径,那么达到第一个位置应该是一条路径,所以要确保dp[1][1] = 1 的话,我们只需要 dp[0][1] 或者 dp[1][0] 其中一个等于 1 即可,其他全部初始化为0,就可以确保我们的第一行和第一列的正确性。

接下来是填表顺序:因为我们的状态转移方程是需要上一个和左边一个的状态值,所以我们需要先把左边和上面的状态值填完,也就是说填表顺序应该为 从上到下,从左到右。

最后就是返回值,因为题目要求到达终点一共有多少条路径,我们直接返回 dp[m][n] 即可,也就是 dp 表的最后一个位置。

class Solution {
    public int uniquePaths(int m, int n) {
        //建表
        int[][] dp = new int[m+1][n+1];
        //初始化
        dp[0][1] = 1;
        //填表
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        //返回值
        return dp[m][n];
    }
}

不同路径Ⅱ

https://leetcode.cn/problems/unique-paths-ii

在这里插入图片描述


解析:
状态表示:达到 某一个位置一共有多少条路径

状态转移方程:dp[i][j] = dp[i-1][j] + dp[i][j-1]

初始化:因为要用到左边和上边的状态数值,所以上面多开一行,右边多开一列,然后dp[0][1] 或者 dp[1][0] 其中一个设置为 1 ,保证填表的正确性。

填表顺序:从上往下,从左往右

返回值:dp[m][n]

细节处理:因为我们不能通过障碍物,所以遇到障碍物的状态值应该写 0, 不需要状态转移方程来推到其状态值

class Solution {
    public int uniquePathsWithObstacles(int[][] ob) {
        //构建 dp 表
        int m = ob.length;
        int n = ob[0].length;
        int[][] dp = new int[m+1][n+1];
        //初始化
        dp[0][1] = 1;
        //填表
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                if(ob[i-1][j-1] != 1) {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        //返回值
        return dp[m][n];
    }
}

珠宝的最高价值

https://leetcode.cn/problems/li-wu-de-zui-da-jie-zhi-lcof

在这里插入图片描述


解析:
状态表示:到达某一个位置能获得的珠宝的最大价值

状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + jewelleryValue[i][j]

初始化,为了填表方便,多开空间。
要保证第一行和第一列的正确性,我们只要保证 dp 表的初始状态值为 0 即可,也就不需要什么额外处理了。
注意下标,因为我们多开了空间,如果要访问原数组必须你的 i, j 应该都减去 1,即 jewelleryValue[i-1][j-1]

填表顺序:从上到下,从左到右

返回值:dp[m][n]

class Solution {
    public int jewelleryValue(int[][] frame) {
        //建表
        int m = frame.length;
        int n = frame[0].length;
        int[][] dp = new int[m+1][n+1];
        //填表
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]) + frame[i-1][j-1];
            }
        }
        //返回值
        return dp[m][n];
    }
}

下降路径最小和

https://leetcode.cn/problems/minimum-falling-path-sum

在这里插入图片描述


解析:
状态表示:到达某个位置的路径最小和设为状态值

状态转移方程:要求出某一个位置的状态值,需要利用上面和对角线的左边与右边的状态值。dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j-1]) + 该位置在原数组的数值。

初始化,因为我们要利用三个状态值,为了避免越界,所以我们多开三个空间,左边一列,上面一行,右边一列:
在这里插入图片描述
为了确保全表正确,也就是不能让多开的空间影响到我们的状态值,所以最上面一行设置为 0,左边一列和右边一列设置为 Integer.MAX_VALUE

在这里插入图片描述

填表顺序:上到下,左到右

返回值,遍历最后一行获得最小值然后返回即可。

class Solution {
    public int minFallingPathSum(int[][] matrix) {
        //建表
        int n = matrix.length;
        int[][] dp = new int[n+1][n+2];
        //初始化
        for(int i = 0; i <= n; i++) {
            dp[i][0] = dp[i][n+1] = Integer.MAX_VALUE;
        }
        Arrays.fill(dp[0], 0);
        //填表
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                dp[i][j] = Math.min(Math.min(dp[i-1][j-1], dp[i-1][j]), dp[i-1][j+1]) + matrix[i-1][j-1];
            }
        }
        //返回值
        int ret = Integer.MAX_VALUE;
        for(int i = 1; i <= n; i++) {
            ret = Math.min(ret, dp[n][i]);
        }
        return ret;
    }
}

最小路径和

https://leetcode.cn/problems/minimum-path-sum

在这里插入图片描述


解析:
状态表示:到达某一个位置的路径最小和

状态转移方程:dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 该位置在原数组的数值

初始化:多开上面一行和左边一列的空间,为了保证填表的正确性,多开的空间先全部设置为 Integer.MAX_VALUE,然后将 dp[0][1] 或者 dp[1][0] 设置为 0 即可。

填表顺序:从上到下,从左到右

返回值:dp[m][n]

class Solution {
    public int minPathSum(int[][] grid) {
        //建表
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m+1][n+1];
        //初始化
        for(int i = 0; i <= m; i++) {
            dp[i][0] = Integer.MAX_VALUE;
        }
        Arrays.fill(dp[0], Integer.MAX_VALUE);
        dp[0][1] = 0;
        //填表
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i-1][j-1];
            }
        }
        //返回值
        return dp[m][n];
    }
}

地下城游戏

https://leetcode.cn/problems/dungeon-game

在这里插入图片描述


解析:
状态表示:到达某一个位置时所需要的最低血量,这个状态表示是不能推导出状态转移方程的,假设你硬推,大概率是推出 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 原数组对应的数值。可是这个方程是错误的,因为你到了 i, j 这个位置得到的最低血量可能不能支撑后面的前进,所以你的状态转移方程还需要考虑后面的情况,可是你考虑不到了,因为后面的状态值根本就还没填你是无法获取的,因此这个状态表示是不可行的。

那么我们就要另辟蹊径了,状态表示除了以某个位置结尾还可以以某个位置为起点,那么我们现在使用以某个位置为起点的形式来看看能不能推导出来。

那么新的状态表示应该为 从某一个位置出发所需要的最低血量。

状态转移方程:要想获得 dp[i][j] 就要知道右边和下面所需要的最低血量,求出其中的最小值,而右边和下面所需要的最低血量正好对应我们的状态表示,即右边的最低血量为 dp[i][j+1] ,下面的最低血量为 dp[i+1][j],那么状态转移方程为 dp[i][j] = min(dp[i+1][j],dp[i][j+1]) - 原数组对应的数值。这方程是这样推导的:首先该位置的最低血量 + 原数组对应的数值 要等于到往下一个位置的 最低血量,然后移项就可以得到上面的状态转移方程

这里还有一个细节:如果原数组是一个血包,也就是一个正数,是有可能让我们的 状态值推导为 小于等于 0 的,这个状态值骑士都死了,还救什么公主,所以这种情况我们要判断如果是则直接设置为 1。

初始化:因为我们的状态推导需要用到右边和下边的状态值,所以为了避免越界和方便填表,我们下面多开一行,右边多开一列。然后就是要保证填表的正确性,也就是保证我们右边和下面的状态值不因为多开的空间而发生错误。首先先来考虑右下角:
在这里插入图片描述
首先要明确绿色的框框是我们救出公主后达到这里多需要的最低血量,应该为 1, 因为骑士的血量不能为0也不能为负值否则就直接死亡了,死了根本就道理绿色区域。

剩余蓝色的区域我们应该设置为 Integer.MAX_VALUE,避免蓝色区域影响到我们的填表正确性。

填表顺序:根据状态转移方程,我们需要先知道右边和下面的状态值才能进行推导,所以从下到上,从右到左进行填表。

返回值:从左上角到右下角所需要的最低血量,返回 dp[0][0] 即可。

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        //建表
        int m = dungeon.length;
        int n = dungeon[0].length;
        int[][] dp = new int[m+1][n+1];
        //初始化
        for(int i = 0; i <= m; i++) {
            dp[i][n] = Integer.MAX_VALUE;
        }
        Arrays.fill(dp[m], Integer.MAX_VALUE);
        dp[m-1][n] = dp[m][n-1] = 1;
        //填表
        for(int i = m - 1; i >= 0; i--) {
            for(int j = n - 1; j >= 0; j--) {
                dp[i][j] = Math.min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j];
                if(dp[i][j] <= 0) 
                    dp[i][j] = 1;
            }
        }
        //返回值
        return dp[0][0];
    }
}

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

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

相关文章

Linux - 信号

文章目录 一、信号的定义二、查看信号三、产生信号1、指令2、系统调用3、由软件条件产生信号4、异常5、键盘输入 四、保存信号1、补充&#xff1a;信号其他相关概念2、信号保存在哪&#xff0c;怎么保存&#xff1f;3、信号集操作函数 五、捕获信号1、概念2、捕获信号的时机3、…

group_concat配置影响程序出bug

在 ThinkPHP 5 中&#xff0c;想要临时修改 MySQL 数据库的 group_concat_max_len 参数&#xff0c;可以使用 原生 SQL 执行 来修改该值。你可以通过 Db 类来执行 SQL 语句&#xff0c;从而修改会话&#xff08;Session&#xff09;级别的变量。 步骤 设置 group_concat_max_l…

云专线优势有哪些?对接入网络有什么要求?

云专线是一种连接企业本地数据中心与云服务提供商之间的专用网络连接方式&#xff0c;具有以下优势&#xff1a; 高安全性&#xff1a;云专线提供了物理隔离的数据传输通道&#xff0c;减少了数据在公共互联网上传输时可能遭遇的安全风险。 低延迟&#xff1a;由于是直接连接&a…

【提高篇】3.1 GPIO(二,结构与工作模式介绍)

目录 一,GPIO的基本结构 1.1 保护二极管 1.2 上拉、下拉电阻 1.3 施密特触发器 1.4 P-MOS 管和 N-MOS 管 P-MOS管和N-MOS管的区别 1.5 片上外设 1.6 IDR,ODR,BSRR寄存器 1.6.1 IDR(Input Data Register) 1.6.2 ODR(Output Data Register) 1.6.3 BSRR(Bit Se…

数据迁移: 安全高效转移数据, 满足企业业务需求和技术改进

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据存储、数据恢复、数据备份、数据迁移等解决方案与服务&#xff0c;并针对企业面临的数据安全风险&#xff0c;提供专业的相关数据安全培训。 鸿萌数据迁移业务为众多企业顺利高效…

Am I Isolated:一款安全态势基准测试工具

基于Rust的容器运行时扫描器作为一个容器运行&#xff0c;检测用户容器运行时隔离中的漏洞。 它还提供指导&#xff0c;帮助用户改善运行时环境&#xff0c;以提供更强的隔离保证。 容器的现状是它们并不包含&#xff08;隔离&#xff09;。 容器隔离的缺失在云原生环境中有…

战略共赢 软硬兼备|云途半导体与知从科技达成战略合作

2024年11月5日&#xff0c;江苏云途半导体有限公司&#xff08;以下简称“云途”或“云途半导体”&#xff09;与上海知从科技有限公司&#xff08;以下简称“知从科技”&#xff09;达成战略合作&#xff0c;共同推动智能汽车领域高端汽车电子应用的开发。 云途半导体与知从科…

基于卷积神经网络的农作物病虫害识别系统(pytorch框架,python源码)

更多图像分类、图像识别、目标检测等项目可从主页查看 功能演示&#xff1a; 基于卷积神经网络的农作物病虫害检测&#xff08;pytorch框架&#xff09;_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积神经网络的农作物病虫害识别系统是在pytorch框架下实现的…

2-149 基于matlab的LDPC译码性能分析

基于matlab的LDPC译码性能分析&#xff0c;LDPC&#xff08;Low-Density Parity-Check&#xff09;码作为编码技术&#xff0c;具有优秀的纠错性能和较低的编解码复杂度。为保证可靠的数据传输&#xff0c;对传输过程中可能出现的信道噪声、干扰等进行模拟和分析。分析对比了误…

算法每日双题精讲——双指针(快乐数,盛最多水的容器)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…

在Scrapy爬虫中应用Crawlera进行反爬虫策略

在互联网时代&#xff0c;数据成为了企业竞争的关键资源。然而&#xff0c;许多网站为了保护自身数据&#xff0c;会采取各种反爬虫技术来阻止爬虫的访问。Scrapy作为一个强大的爬虫框架&#xff0c;虽然能够高效地抓取网页数据&#xff0c;但在面对复杂的反爬虫机制时&#xf…

Linux(CentOS)安装 JDK

CentOS版本&#xff1a;CentOS 7 JDK版本&#xff1a;JDK17 1、下载 JDK 官网&#xff1a;https://www.oracle.com/ 2、上传 JDK 文件到 CentOS 使用FinalShell远程登录工具&#xff0c;并且使用 root 用户连接登录&#xff08;注意这里说的root用户连接登录是指这样的&…

redis和数据库的数据一致性

在我们使用redis作为缓存的时候&#xff0c;数据库和缓存数据保持一致性就显得尤为重要&#xff0c;因为如果不做处理的话很有可能读取到的数据会出现差错&#xff0c;那这里怎么进行解决呢&#xff1f; 首先我们先来看一下操作数据到底是直接删除数据还是说通过修改的方式来修…

发布 VectorTraits v3.0(支持 X86架构的Avx512系列指令集,支持 Wasm架构及PackedSimd指令集等)

文章目录 支持 X86架构的Avx512系列指令集支持Avx512时的输出信息 支持 Wasm架构及PackedSimd指令集支持PackedSimd时的输出信息VectorTraits.Benchmarks.Wasm 使用说明 新增了向量方法支持 .NET 8.0 新增的向量方法提供交织与解交织的向量方法YGroup3Unzip的范例代码 提供重新…

工业相机常用功能之白平衡及C++代码分享

目录 1、白平衡的概念解析 2、相机白平衡参数及操作 2.1 相机白平衡参数 2.2 自动白平衡操作 2.3 手动白平衡操作流程 3、C++ 代码从XML读取参数及设置相机参数 3.1 读取XML 3.2 C++代码,从XML读取参数 3.3 给相机设置参数 1、白平衡的概念解析 白平衡(White Balance)…

推荐一款SSD硬盘优化器:Auslogics SSD Optimizer Pro

SSD Optimizer Pro 是一款专为优化固态硬盘 (SSD) 性能而设计的专业工具&#xff0c;旨在最大化 SSD 的效率&#xff0c;延长硬盘使用寿命。凭借简便的操作界面和强大的优化功能&#xff0c;SSD Optimizer Pro 可以让用户充分利用 SSD 的优势&#xff0c;从而获得更高的系统性能…

常用机器人算法原理介绍

一、引言 随着科技的不断发展&#xff0c;机器人技术在各个领域得到了广泛应用。机器人算法是机器人实现各种功能的核心&#xff0c;它决定了机器人的行为和性能。本文将介绍几种常用的机器人算法原理&#xff0c;包括路径规划算法、定位算法和运动控制算法。 二、路径规划算法…

基于开源 AI 智能名片 S2B2C 商城小程序的视频号交易小程序优化研究

摘要&#xff1a;本文探讨了完善适配视频号交易小程序的重要意义&#xff0c;重点阐述了开源 AI 智能名片 S2B2C 商城小程序在这一过程中的应用。通过分析其与直播间和社群的无缝衔接特点&#xff0c;以及满足新流量结构下基础设施需求的能力&#xff0c;为门店在视频号直播交易…

【OH】openHarmony开发环境搭建(基于windows子系统WSL)

前言 本文主要介绍基于windows子系统WSL搭建openHarmony开发环境。 WSL与Vmware虚拟机的区别&#xff0c;可以查看WSL与虚拟机的区别 更详细的安装配置过程可参考微软官网&#xff1a; ​安装 WSL 前提 以下基于windows 111专业版进行配置&#xff0c;windows 10应该也是可以…

WPF使用Prism框架首页界面

1. 首先确保已经下载了NuGet包MaterialDesignThemes 2.我们通过包的项目URL可以跳转到Github上查看源码 3.找到首页所在的代码位置 4.将代码复制下来&#xff0c;删除掉自己不需要的东西&#xff0c;最终如下 <materialDesign:DialogHostDialogTheme"Inherit"Ide…