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

2024-06-14 23:04

本文主要是介绍【动态规划】| 详解路径问题之地下城游戏 力扣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 .。.:*☆

这篇关于【动态规划】| 详解路径问题之地下城游戏 力扣174 (困难题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1061744

相关文章

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细... 目录【1】saveBATch(一万条数据总耗时:2478ms)【2】集合方式foreach(一万条数

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

使用Python实现矢量路径的压缩、解压与可视化

《使用Python实现矢量路径的压缩、解压与可视化》在图形设计和Web开发中,矢量路径数据的高效存储与传输至关重要,本文将通过一个Python示例,展示如何将复杂的矢量路径命令序列压缩为JSON格式,... 目录引言核心功能概述1. 路径命令解析2. 路径数据压缩3. 路径数据解压4. 可视化代码实现详解1

Python装饰器之类装饰器详解

《Python装饰器之类装饰器详解》本文将详细介绍Python中类装饰器的概念、使用方法以及应用场景,并通过一个综合详细的例子展示如何使用类装饰器,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录1. 引言2. 装饰器的基本概念2.1. 函数装饰器复习2.2 类装饰器的定义和使用3. 类装饰

Spring 中的循环引用问题解决方法

《Spring中的循环引用问题解决方法》:本文主要介绍Spring中的循环引用问题解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录什么是循环引用?循环依赖三级缓存解决循环依赖二级缓存三级缓存本章来聊聊Spring 中的循环引用问题该如何解决。这里聊

MySQL 中的 JSON 查询案例详解

《MySQL中的JSON查询案例详解》:本文主要介绍MySQL的JSON查询的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql 的 jsON 路径格式基本结构路径组件详解特殊语法元素实际示例简单路径复杂路径简写操作符注意MySQL 的 J

Spring Boot中JSON数值溢出问题从报错到优雅解决办法

《SpringBoot中JSON数值溢出问题从报错到优雅解决办法》:本文主要介绍SpringBoot中JSON数值溢出问题从报错到优雅的解决办法,通过修改字段类型为Long、添加全局异常处理和... 目录一、问题背景:为什么我的接口突然报错了?二、为什么会发生这个错误?1. Java 数据类型的“容量”限制

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

关于MongoDB图片URL存储异常问题以及解决

《关于MongoDB图片URL存储异常问题以及解决》:本文主要介绍关于MongoDB图片URL存储异常问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录MongoDB图片URL存储异常问题项目场景问题描述原因分析解决方案预防措施js总结MongoDB图