【动态规划】| 详解路径问题之地下城游戏 力扣174 (困难题)

🎗️ 主页:小夜时雨
🎗️专栏:动态规划
🎗️如何活着,是我找寻的方向

优雅

目录

  • 1. 题目解析
  • 2. 代码

1. 题目解析

题目链接: https://leetcode.cn/problems/minimum-path-sum/description/
在这里插入图片描述
在这里插入图片描述

建议先看一下前面的几道题加深理解一下, 本道题是一个反方向思考
不同路径1 :https://leetcode.cn/problems/unique-paths/description/
不同路径2: https://blog.csdn.net/Jin__Wang/article/details/139623230
最小路径和:https://blog.csdn.net/Jin__Wang/article/details/139653515

这道题的难度是困难, 要是把前面文章关于路径问题的题之后, 这道题理解起来还是可以的,与常规的题目是正好相反的,具体地一一介绍。

通常动态规划的题目有五个大步骤进行解析, 本道题也不例外我们来一一进行分析。

1. 状态表示

动态规划的重点是状态表示, 我们通过状态表示才可以写出正确的状态转移方程, 状态表示我们通常都是根据 经验+题目 要求来进行定义的.

  • 但是注意本道题目用我们之前的经验来定义状态表示,后续是推导不出来状态转移方程的。

比如本道题又是一个二维的矩阵, 可以以另一种经验来定义状态表示:即从某个位置为起点,达到终点 + 题目要求。
以本题为例, 状态表示可以写为:

dp[i][j]: 从 (i, j) 这个位置出发,到达终点, 所需的最低健康点数

和之前的状态表示是反过来的,之前都是以(i,j) 为终点,本题则是表示为起点。

2. 状态转移方程

  • 根据状态表示, (i,j)是起点,那么就可以往下走到达(i + 1, j)位置,或者往右走到达(i,j + 1)位置。
  • 根据状态表示, dp[i][j] 的大小可以由两部分组成, 问的是最低点数, 那么共有两条不同的路径: 从往右走或者从往下走,求的应该是这二者中的最小值。
  • 从 (i, j) 走到终点所需的最低点数为 dp[i][j] , 那么从 (i + 1, j) 走到 走到终点所需的最低点数为 dp[i + 1][j], 因为要求点数必须是正整数,所以有 dp[i][j]+ nums[i][j] >= dp[i + 1][j], 才能走到终点。同理 dp[i][j + 1] 也是.
  • 那么 dp[i][j] >= dp[i + 1][j] - nums[i][j]. 这是往下走的情况, 往右走的情况同理,求二者中的最小值。

dp[i][j] = Math.min(dp[i + 1][j],dp[i][j + 1]) - nums[i][j]

  • 细节问题:题目要求点数 必须为正整数, 有可能计算出来的 dp[i][j] 为一个负数,
  • 表示最低点数是一个负值, 然后到达(i,j)是一个超大的正数,加上之后走到了终点,不符合实际情况,所以血量至少为1,所以多加一个比较条件。dp[i][j] > 0的时候没变化, <=0 的时候则会设置为1。
  • 所以状态转移方程应该为:

dp[i][j] = Math.min(dp[i + 1][j],dp[i][j + 1]) - nums[i][j]
dp[i][j] = Math.max(1,dp[i][j)

  • 细节问题2: 前面几题都提过的下标映射.这里和不同路径1 不同的是, 这里需要用到原数组,我们通常也是采取多加一行一列的方式来避免出现 dp 表越界的情况, 所以要注意映射关系。
  • 但是因为我们是加的是最后一行和最后一列,遍历也是反过来的,所以下标还是对应上的,所以遍历 dp 表填表的过程中的 (i, j)对应原数组的值是 nums[i][j]。 和之前还是不一样

在这里插入图片描述

3. 初始化

细节问题: 观察状态转移方程可知, 有可能会有越界的风险, 此处我们依旧采取一种多加一行一列的方式来进行初始化.多加一行一列要保证两点:

  1. 虚拟节点的值要保证后面的dp 表里的值是正确的
  2. 要注意下标的映射关系. 因为我们是多加了一行一列, 所以对应到原始数组就应该行列要减一. (此处用到了原数组, 所以要有这个映射关系)

注意 :
这道题的初始化和前几道题依旧是相反的。

注意到我们计算 dp[i][j] 的时候是用到下一行的数据和本行右侧的数据,所以填表顺序也是反的, 初始化也是反的,需要初始化最后一行最后一列。

  • 本题的初始化方式和 最小路径和类似,不过初始位置是最后一行最后一列。

  • 最小路径和:https://blog.csdn.net/Jin__Wang/article/details/139653515

  • 根据实际情况来,救完公主到达 (m, n)位置后,往右走或者往下走,保证救完公主之后的点数最低为1, 所以 dp[m][n - 1] = dp[m - 1][n] = 1

  • 其余的位置因为求的是最小值,所以不要干扰到结果,应该和最小路径和一样其余位置更新为最大值

  • 例如观察下图我们发现,填写 dp[1][1] 的时候需要用到左边和上边值, 因为求的是二者中的最小值, 为了不干扰结果, 设置为0即可。

  • 看下图,但是填写 dp[m - 1][n - 2] 的时候,需要用到下面的值 dp[m][n - 2] 和 dp[m - 1][n - 1] 作比较求最小值,倘如是dp[m][n - 2] 还是默认初始化为 0 的话, 就会影响结果,有可能使 dp[m - 1][n - 2] = dp[m][n - 2] - nums[m - 1][n - 1, 此时dp[m][n - 2] 为0,就导致错误了.

  • 实际情况应该是 dp[m - 1][n - 2] 本该是只有一条路径, 那就是从到 (m - 1,n - 2)走到(m - 1,n - 1),就应该是 dp[m - 1][n - 2] = dp[m - 1][n - 1] - nums[m - 1][n - 1]. 观察结果,因为求一个最小值,让 dp[m][n - 2] 是一个非常大的数字,不影响结果即可。此处通常我们设置为整数最大值或者 0x3f3f3f3f.

看图更容易理解
在这里插入图片描述

4. 填表顺序

观察可知, 填 (i, j) 的值的时候需要用到下一行和右边的值. 所以填表顺序是 从下往上, 从右往左.

5. 返回值

根据题目的要求, 从起点(0,0)要到达(m, n) 的最小健康点数, 正好对应 dp[0][0] 的表示. 所以返回 dp[0][0] 即可,和之前的题目返回值也是不同的。

2. 代码

这道题难在思路都是反过来的,5个分析的过程和之前都是不一样的。

动态规划的代码编写一般都是分为 4 个步骤进行:

  1. 创建 dp 表
  2. 初始化
  3. 填表
  4. 返回值
   // 完全跟前面的题完全反过来了: 包括状态表示, 方程, 和填表顺序public int calculateMinimumHP(int[][] dungeon) {// ×××××××dp[i]状态表示: 从起点左上角到达(i,j) 位置的最小健康点数 这种找不出状态方程××××// dp[i]状态表示: 从(i,j) 位置到达终点所需的最小健康点数// 1.创建 dp表// 2.初始化// 3.填表// 4.返回值// 动态规划 这里的是二维, 所以时空都是O(M*N)int m = dungeon.length, n = dungeon[0].length;int[][] dp = new int[m + 1][n + 1];// 初始化, 新加的最右边一列和最下边一列// 都需要进行初始化为最大值 (因为求的是最小值, 默认的0有可能干扰结果)for(int i = 0; i <= m; i++) dp[i][n] = Integer.MAX_VALUE; //新增行for(int j = 0; j <= n; j++) dp[m][j] = Integer.MAX_VALUE; //新增列// dp[0][1] = dp[1][0] = 0; // 特殊处理边界dp[m][n - 1] = dp[m - 1][n] = 1;// 做好映射关系, 这里因为添加的是右下角的行和列, 所以不需要映射// 这里填的是 dp 表, 所以建议从(1,1) 开始. 也就是dp表多加了一行一列// 遍历的是 dp 表for(int i = m - 1; i >= 0; i--) { // 从xia往上每一行 和之前反过来了for(int j = n - 1; j >= 0; j--) { // 从you往左每一列// dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + dungeon[i - 1][j - 1]; 这是之前的写法, 这道题是反过来的dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];dp[i][j] = Math.max(1, dp[i][j]); //细节问题:防止血量有负数}}// return dp[m][n];return dp[0][0];}

🎗️🎗️🎗️ 好啦,到这里有关本题的分享就没了,如果感觉做的还不错的话可以点个赞,关注一下,你的支持就是我继续下去的动力,我们下期再见,拜了个拜~ ☆*: .。. o(≧▽≦)o .。.:*☆

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

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

相关文章

Character Region Awareness for Text Detection论文学习

​1.首先将模型在Synth80k数据集上训练 Synth80k数据集是合成数据集&#xff0c;里面标注是使用单个字符的标注的&#xff0c;也就是这篇文章作者想要的标注的样子&#xff0c;但是大多数数据集是成堆标注的&#xff0c;也就是每行或者一堆字体被整体标注出来&#xff0c;作者…

手把手教你安装 Vivado2022.2(附安装包)

​一、Vivado 2022.2 优势 Vivado 2022.2版本与之前的版本相比&#xff0c;具有以下几个显著的优势&#xff1a; 电源设计管理器&#xff08;PDM&#xff09;&#xff1a;Vivado 2022.2引入了全新的电源设计管理器&#xff08;PDM&#xff09;&#xff0c;这是一个下一代功耗评…

LeetCode | 58.最后一个单词的长度

这道题要求最后一个单词的长度&#xff0c;第一个想到的就是反向遍历字符串&#xff0c;寻找最后一个单词并计算其长度。由于尾部可能会有’ &#xff0c;所以我们从后往前遍历字符串&#xff0c;找到第一个非空格的字符&#xff0c;然后记录下到下一个空格前依次有多少个字母即…

python全栈开发《05.环境搭建与脚本结构之python中的关键字》

1.什么是关键字 在中国古代&#xff0c;像皇帝&#xff0c;还有官员的官职&#xff0c;他们的官称不同&#xff0c;所执行的工作内容也并不相同。 那么python里面的关键字就像朝廷里面官员的头衔一样被python所内定。并且起到各自的功能。朝廷的官员是为了国家的运转而存在的。…

【思维导图工具】Xmind 2024安装教程+软件安装包下载

​XMind 2022是一款风靡全宇宙的思维导图和头脑暴炸软件&#xff0c;是全宇宙领先的“可视化思考”工具&#xff0c;每一个功能都能帮助你激发灵感、提高创造力。 XMind 2022为不同的使用场景提供多种可视化布局&#xff0c;让你的思维可以更清晰的结构化呈现&#xff0c;该软件…

Apollo9.0 PNC源码学习之Control模块(二)—— controller解析

前面文章&#xff1a;Apollo9.0 PNC源码学习之Control模块&#xff08;一&#xff09; 本文将对具体控制器以及原理做一个剖析 1 PID控制器 1.1 PID理论基础 如下图所示&#xff0c;PID各参数(Kp,Ki,Kd)的作用&#xff1a; 任何闭环控制系统的首要任务是要稳、准、快的响…

水表摄像直读抄表仪

1.技术性简述 水表摄像直读抄表仪&#xff0c;是一种前沿的智能计量机器设备&#xff0c;它利用超清摄像头部和图像识别算法&#xff0c;完成了远程控制、非接触的水表载入。这一技术的普及&#xff0c;颠覆了传统式人力抄表的形式&#xff0c;提高了效率&#xff0c;降低了不…

RPA-UiBot6.0控制与运行机器人 —工作任务智能调度自动运行

前言 来也产品文档中心 来也产品文档中心 (laiye.com)https://documents.laiye.com/ 友友们你们是否曾因为例行性工作的繁琐而苦恼&#xff1f;是否想要让机器人帮你自动执行这些任务&#xff1f;小北的这篇博客将为友友们揭示其中的奥秘&#xff0c;让我们一起学习如何通过RP…

计算机组成原理历年考研真题对应知识点(计算机系统层次结构)

目录 1.2计算机系统层次结构 1.2.2计算机硬件 【命题追踪——冯诺依曼计算机的特点(2019)】 【命题追踪——MAR 和 MDR 位数的概念和计算(2010、2011)】 1.2.3计算机软件 【命题追踪——三种机器语言的特点(2015)】 【命题追踪——各种翻译程序的概念(2016)】 1.2.5计算…

2024.6.14 刷题总结

2024.6.14 **每日一题** 2786.访问数组中的位置使分数最大&#xff0c;看到这题就想到动态规划的思路&#xff0c;遍历数组&#xff0c;每次选择移动该元素时能获得到的最大值&#xff0c;分别考虑最后一个的元素为奇数/偶数的最大值&#xff0c;用长度为2的数组来储存这两个值…

HTML解析之Beautiful Soup

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Beautiful Soup是一个用于从HTML和XML文件中提取数据的Python库。Beautiful Soup 提供一些简单的、函数用来处理导航、搜索、修改分析树等功能。Beau…

代码随想录:回溯20-21

51.N皇后 题目 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解…

【深度学习】Transformer分类器,CICIDS2017,入侵检测,随机森林、RFE、全连接神经网络

文章目录 1 前言2 随机森林训练3 递归特征消除 RFE Recursive feature elimination4 DNN5 Transformer5.1. 输入嵌入层&#xff08;Input Embedding Layer&#xff09;5.2. 位置编码层&#xff08;Positional Encoding Layer&#xff09;5.3. Transformer编码器层&#xff08;T…

堆的实现及其应用

堆的概念 堆是完全二叉树&#xff0c;分为大堆和小堆。大堆&#xff1a;任何一个父亲都大于等于孩子&#xff0c;小堆&#xff1a;任何一个父亲都小于等于孩子。 堆的实现 目录 typedef int HPDataType;typedef struct Heap { HPDataType* a;int size;int capacity; }HP;//交…

C语言之操作符

目录 一、二进制 原码、反码、补码 二、移位操作符 位操作符 三、 逗号表达式 四、下标访问[]、函数调用() 五. 操作符的属性 整型提升 算术转换 六、总结 一、二进制 其实2进制、8进制、10进制、16进制是数值的不同表示形式而已。 其实10进制是生活中经常使用的&am…

类别朴素贝叶斯CategoricalNB和西瓜数据集

CategoricalNB 1 CategoricalNB原理以及用法2 数据集2.1 西瓜数据集2.2 LabelEncoder2.3 OrdinalEncoder 3 代码实现 1 CategoricalNB原理以及用法 &#xff08;1&#xff09;具体原理 具体原理可看&#xff1a;贝叶斯分类器原理 sklearn之CategoricalNB对条件概率的原理如下&…

粉丝经济时代:微信订阅号如何助力中小企业增长

在数字化浪潮席卷全球的今天&#xff0c;微信订阅号凭借其独特的优势&#xff0c;成为了中小企业数字化出海的重要工具。作为NetFarmer&#xff0c;我们致力于帮助企业充分利用这一平台&#xff0c;推动业务发展和市场拓展。今天将深入探讨微信订阅号的概念、用途、使用方法、适…

mac安装高版本git(更新git)

问题 问题&#xff1a;新下载的idea&#xff0c;此idea的版本较高&#xff0c;但是在工作发现这个版本的git存在一定漏洞会导致一些信息泄露问题。 1.安装Homebrew 对于Mac更新git&#xff0c;最简单的就是使用brew命令。所以我们首先下载homebrew。已下载的同学忽略直接下一…

【数据结构陈越版笔记】进阶实验1-3.1:两个有序序列的中位数

我这答案做的可能不对&#xff0c;如果不对&#xff0c;欢迎大家指出错误&#xff0c;思路大部分直接写在注释中了。 进阶实验1-3.1&#xff1a;两个有序序列的中位数 已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列 A 0 , A 1 , . . . , A n −…

ES升级--05--快照生成 和备份

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 备份ES数据1.关闭集群自动均衡2.执行同步刷新3.停止集群节点的Elasticsearch服务4.修改Elasticsearch配置文件&#xff0c;开启快照功能&#xff0c;配置仓库目录为…