【LeetCode】--- 动态规划 集训(二)

news2024/10/7 6:41:58

目录

  • 一、63. 不同路径 II
    • 1.1 题目解析
    • 1.2 状态转移方程
    • 1.3 解题代码
  • 二、931. 下降路径最小和
    • 2.1 题目解析
    • 2.2 状态转移方程
    • 2.3 解题代码
    • 三、174. 地下城游戏
    • 3.1 题目解析
    • 3.2 状态转移方程
    • 3.3 解题代码

一、63. 不同路径 II

题目地址: 不同路径 II


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

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
在这里插入图片描述
从左上角到右下角一共有 2 条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右

1.1 题目解析

状态表示:

对于这种「路径类」的问题,我们的状态表示⼀般有两种形式

  1. [i, j]位置出发,到达⽬标位置有多少种方式;
  2. 从起始位置出发,到达 [i, j]位置,,⼀共有多少种方式。

这⾥选择第⼆种定义状态表示的方式:dp[i][j]表示:走到 [i, j]位置处,⼀共有多少种方式。

状态转移:

简单分析⼀下。如果 dp[i][j]表示到达 [i, j]位置的方法数,那么到达 [i, j]位置之前的⼀小步,有两种情况:

  1. [i, j]位置的上方( [i - 1, j]的位置)向下走一步,转移到 [i, j]位置;
  2. [i, j]位置的左方( [i, j - 1]的位置)向右⾛⼀步,转移到 [i, j]位置。

但是, [i - 1, j][i, j - 1]位置都是可能有障碍的,此时从上⾯或者左边是不可能到达 [i, j]位置的,也就是说,此时的方法数应该是 0。由此我们可以得出⼀个结论,只要这个位置上「有障碍物」,那么我们就不需要计算这个位置上的值,直接让它等于 0 即可。

初始化:

可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:

  1. 辅助结点⾥⾯的值要「保证后续填表是正确的」;
  2. 下标的映射关系」。

在本题中,添加一行,并且添加⼀列后,只需将 dp[1][0]的位置初始化为 1即可。 添加一行和一列是因为[i, j]位置需要[i - 1, j][i, j - 1]两个方位的值,以此确保状态表不越界,将dp[1][0]初始化为1,为了保证在起点时有方法数 1 。

填表顺序:

根据「状态转移」的推导,填表的顺序就是 「从上往下」填每一行,每一行「从左往右」。

返回值:

根据「状态表⽰」,我们要返回的结果是 dp[m][n]

1.2 状态转移方程

从当前位置的上方和左方,到达当前位置的方法数:dp[i][j] = dp[i - 1][j] + dp[i][j - 1];。还需要注意的是若当前位置为障碍物,直接将当前状态置为0(即dp[i][j] = 0;)

1.3 解题代码

class Solution 
{
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) 
    {
        int row = obstacleGrid.size(), col = obstacleGrid[0].size();
        //1. 创建dp表
        vector<vector<int>> dp(row + 1, vector<int>(col + 1));
        //2. 初始化
        dp[0][1] = 1;
        //3. 填表
        //从上到下填表 -> 从左到右填表
        for (int i = 1; i <= row; ++i)
            for (int j = 1; j <= col; ++j)
                if(obstacleGrid[i - 1][j - 1] == 0) dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
        //4. 返回值
        return dp[row][col];
    }
};

二、931. 下降路径最小和

题目地址: 931. 下降路径最小和


给你一个n x n方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径最小和
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置(row, col) 的下一个元素应当是(row + 1, col - 1)(row + 1, col)或者 (row + 1, col + 1)

在这里插入图片描述
输入:matrix = [[2,1,3],[6,5,4],[7,8,9]]
输出:13
解释:如图所示,为和最小的两条下降路径

2.1 题目解析

状态表示:

对于这种「路径类」的问题,我们的状态表示一般有两种形式:

  1. 从 [i, j] 位置出发,到达⽬标位置有多少种方式;
  2. 从起始位置出发,到达 [i, j] 位置,⼀共有多少种方式

这里选择第⼆种定义状态表示的方式:
dp[i][j]表示:到达 [i, j]位置时,所有下降路径中的最小和。

状态转移:

对于普遍位置 [i, j],根据题意得,到达 [i, j]位置可能有三种情况

  1. 从正上方 [i - 1, j]位置转移到 [i, j]位置;
  2. 从左上方 [i - 1, j - 1]位置转移到 [i, j]位置;
  3. 从右上方 [i - 1, j + 1]位置转移到 [i, j]位置;

我们要的是三种情况下的「最小值」,然后再加上矩阵在 [i, j]位置的值。于是 dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i - 1][j + 1])) + matrix[i][j]

初始化:

可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使用这种技巧要注意两个点:

  1. 辅助结点里面的值要「保证后续填表是正确的」;
  2. 下标的映射关系」。

事实上这题的状态转移方程是不难想到的,而关键问题在于初始化。[i, j]位置的值可以从三个方向来 - 上、左、右,所以为了不越界,在本题中,需要「加上一行」,并且「加上两列」(最左边和最右边)。 所有的位置都初始化为无穷大,然后将第一行初始化为 0 即可。将初始值设为无穷大是因为,这些是虚拟节点,不应该对选数造成影响(即大于其他两路的值)。

填表顺序:

根据「状态表示」,填表的顺序是「从上往下」。

返回值:

注意这里不是返回 dp[m][n]的值!
题⽬要求「只要到达最后一行」就行了,因此这⾥应该返回「 dp 表中最后一行的最小值」。

2.2 状态转移方程

dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i - 1][j + 1])) + matrix[i][j];

2.3 解题代码

class Solution 
{
public:
    int minFallingPathSum(vector<vector<int>>& matrix) 
    {
        //1. 创建dp表
        int row = matrix.size(), col = matrix.size();
        vector<vector<int>> dp(row + 1, vector<int>(col + 2, INT_MAX));
        //2. 初始化列表
        //第一行变为0
        for(int i = 0; i < col + 2; ++i) dp[0][i] = 0;
        //3. 填表
        for(int i = 1; i <= row; ++i)
            for(int j = 1; j <= col; ++j)
                dp[i][j] = matrix[i - 1][j - 1] 
                             + min(min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i - 1][j + 1]);
        //4. 返回结果
        int ans = INT_MAX;
        for(int i = 1; i <= col; ++i)
            ans = min(ans, dp[row][i]);
        return ans;
    }
};

三、174. 地下城游戏

题目地址: 174. 地下城游戏


恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快解救公主,骑士决定每次只 向右向下 移动一步。
返回确保骑士能够拯救到公主所需的最低初始健康点数。
注意: 任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

在这里插入图片描述
输入:dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
输出:7
解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7 。

3.1 题目解析

状态表示:

这道题如果我们定义成:从起点开始,到达 [i, j]位置的时候,所需的最低初始健康点数。那么我们分析状态转移的时候会有⼀个问题:那就是我们当前的健康点数还会受到后面的路径的影响。也就是从上往下的状态转移不能很好地解决问题。

这个时候我们要换⼀种状态表示:[i, j]位置出发,到达终点时所需要的最低初始健康点数。 这样我们在分析状态转移的时候,后续的最佳状态就已经知晓。

综上所述,定义状态表示为:
dp[i][j]表示:从 [i, j]位置出发,到达终点时所需的最低初始健康点数。

状态转移方程:

对于 dp[i][j],从 [i, j]位置出发,下⼀步会有两种选择(为了方便理解,设 dp[i][j]的最终答案是 x ):

  1. 走到右边,然后走向终点:
    那么我们在 [i, j]位置的最低健康点数加上这⼀个位置的消耗,应该要⼤于等于右边位置的最低健康点数,也就是: x + dungeon[i][j] >= dp[i][j + 1]。通过移项可得: x >= dp[i][j + 1] - dungeon[i][j]。因为我们要的是最小值,因此这种情况下的 x = dp[i][j + 1] - dungeon[i][j]
  2. 走到下边,然后走向终点:
    那么我们在 [i, j]位置的最低健康点数加上这⼀个位置的消耗,应该要大于等于下边位置的最低健康点数,也就是: x + dungeon[i][j] >= dp[i + 1][j]。通过移项可得: x >= dp[i + 1][j] - dungeon[i][j]。因为我们要的是最小值,因此这种情况下的 x = dp[i + 1][j] - dungeon[i][j]

综上所述,我们需要的是两种情况下的最小值,因此可得状态转移方程为:dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]

但是,如果当前位置的 dungeon[i][j]是⼀个比较大的正数的话, dp[i][j]的值可能变成 0 或者负数。也就是最低点数会小于 1 ,那么骑士就会死亡。因此我们求出来的 dp[i][j]如果小于等于 0 的话,说明此时的最低初始值应该为 1 。处理这种情况仅需让 dp[i][j]与 1 取⼀个最大值即可:dp[i][j] = max(1, dp[i][j])

初始化:

可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使用这种技巧要注意两个点:

  1. 辅助结点⾥⾯的值要「保证后续填表是正确的」;
  2. 「下标的映射关系」。

在本题中,在 dp 表最后⾯添加一行,并且添加⼀列后,所有的值都先初始化为⽆穷大,然后让dp[m][n - 1] = dp[m - 1][n] = 1即可。

填表顺序:

根据「状态转移方程」,我们需要「从下往上填每一行」,「每一行从右往左」

返回值:

根据「状态表示」,我们需要返回 dp[0][0]的值。

3.2 状态转移方程

骑士到达当前位置最低健康点数:dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]
确保健康值不低于1:dp[i][j] = max(1, dp[i][j]);

3.3 解题代码

class Solution
{
    public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) 
    {
        int m = dungeon.size(), n = dungeon[0].size();
        // 建表 + 初始化
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
        dp[m][n - 1] = dp[m - 1][n] = 1;
        // 填表
        for(int i = m - 1; i >= 0; i--)
        {
            for(int j = n - 1; j >= 0; j--)
            {
                dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
                dp[i][j] = max(1, dp[i][j]);
            }
        }
        // 返回结果
        return dp[0][0];
    }
};

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

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

相关文章

2024年N1叉车司机证模拟考试题库及N1叉车司机理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年N1叉车司机证模拟考试题库及N1叉车司机理论考试试题是由安全生产模拟考试一点通提供&#xff0c;N1叉车司机证模拟考试题库是根据N1叉车司机最新版教材&#xff0c;N1叉车司机大纲整理而成&#xff08;含2024年…

『VUE』13. Class绑定(详细图文注释)

目录 动态和静态类结合采用数组的方式引入数组语法的动态类名代码演示总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 首先样式类定义 <style> .active {font-size: 50px; } .text-danger {color: red; } </style&g…

一文带你理解完Git知识点

文章目录 Git基础概念Git基本操作**0. 初始化仓库****1. add到暂存区****2. 再commit到本地仓库****3. 推送到远程仓库****4. 拉取远程仓库****5. 撤销更改** Git分支管理1. 创建分支命令2. 切换分支命令3. 摘取提交4. 删除分支命令5. 合并分支命令6. 变基 Git进阶1. **git tag…

计算机网络 实验指导 实验8

三层交换机的访问控制 1.实验拓扑图&#xff1a; 名称接口IP地址网关Switch AF0/1192.168.1.1/24F0/2172.1.1.1/24Switch BF0/1192.168.1.2/24F0/2172.2.2.1/24PC1172.1.1.2/24172.1.1.1PC2172.1.1.3/24172.1.1.1PC3172.2.2.2/24172.2.2.1PC4172.2.2.3/24172.2.2.1 2.实验目的…

Stable Diffusion介绍

Stable Diffusion是一种前沿的开源深度学习模型框架&#xff0c;专门设计用于从文本描述生成高质量的图像。这种称为文本到图像生成的技术&#xff0c;利用了大规模变换器&#xff08;transformers&#xff09;和生成对抗网络&#xff08;GANs&#xff09;的力量&#xff0c;以…

PPT在线压缩工具推荐

有时候使用邮箱发送邮件时&#xff0c;添加的PPT、Word、PDF文档总会因为过大而转为其他类型的附件发送&#xff0c;不仅上传缓慢&#xff0c;对方查收下载时还有有效期限制&#xff0c;7天或15天后就过期再也无法下载了&#xff0c;有没有什么办法可以压缩PPT等文档&#xff0…

基于单片机光伏太阳能跟踪系统设计

**单片机设计介绍&#xff0c;基于单片机光伏太阳能跟踪系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机光伏太阳能跟踪系统的设计&#xff0c;旨在通过单片机技术实现对光伏太阳能设备的自动跟踪&#xff0c;以提高太阳…

五款户外运动耳机推荐,让你畅享户外运动时光

在繁忙的都市生活中&#xff0c;我们常常被各种琐事所困扰&#xff0c;以至于忘记了自然的美丽与宁静。然而&#xff0c;当我们走近大自然&#xff0c;放下心中的烦恼&#xff0c;我们会发现&#xff0c;自然是我们最好的治愈师。热爱自然的朋友们&#xff0c;这里有一份运动耳…

linux进阶篇:磁盘管理(一):LVM逻辑卷基本概念及LVM的工作原理

Linux磁盘管理(一)&#xff1a;LVM逻辑卷基本概念及LVM的工作原理 一、传统的磁盘管理 在传统的磁盘管理方案中&#xff0c;如果我们的磁盘容量不够了&#xff0c;那这个时候应该要加一块硬盘&#xff0c;但是新增加的硬盘是作为独立的文件系统存在的&#xff0c;原有的文件系…

怎么根据ip地址计算子网掩码

在计算机网络的世界中&#xff0c;IP地址和子网掩码扮演着至关重要的角色。IP地址用于标识网络中的每一台设备&#xff0c;而子网掩码则用于区分网络地址和主机地址&#xff0c;进而确定设备在网络中的具体位置。然而&#xff0c;有时我们可能需要根据已知的IP地址来计算子网掩…

A Novel Distributed File System Using Blockchain Metadata——论文泛读

Wireless Personal Communications 2023 Paper 分布式元数据论文阅读笔记整理 问题 随着来自不同来源&#xff08;如在线社交媒体、物联网、移动数据、传感器数据、黑匣子数据等&#xff09;的大量数据以指数级的速度增长&#xff0c;集群计算已成为数据处理中不可避免的一部…

多功能调解室sip可视对讲方案

多功能调解室sip可视对讲方案 人民调解委员会是依法设立的调解民间纠纷的群众性组织。 我国基层解决人民内部纠纷的群众性自治组织.人民调解委员会在城市以居民委员会为单位,农村以村民委员会为单位建立.其任务是: 及时发现纠纷,迅速解决争端.防止矛盾激化,预防,减少犯罪的发生…

Java System类和Runtime类

System常见API exit:退出程序currentTimeMillis &#xff1a;获取当前的毫秒数&#xff08;1970年是c语言诞生的那一年&#xff09; 代码 System.out.println("Hello, World!"); // System.exit(0); // 退出程序 尽量别使用long currentTimeMillis System.currentTi…

咖啡茶饮、便利店、餐厅……连锁门店的人效突围之路

1、连锁门店的人效突围 去年年末&#xff0c;我们有幸访谈了餐饮、茶饮业的一些连锁品牌&#xff0c;有餐厅&#xff0c;茶饮品牌、精品咖啡、便利店……有走在创业路上的新起之秀&#xff0c;也有十几年的老牌企业。他们的门店数量&#xff0c;从几十家、上百家、上千家不等。…

FME学习之旅---day20

我们付出一些成本&#xff0c;时间的或者其他&#xff0c;最终总能收获一些什么。 教程&#xff1a;AutoCAD 入门 FME使用四种主要格式来读取和写入AutoCAD图形文件;初级教程重点介绍AutoDesk AutoCAD DWG\DXF(ACAD) AutoCAD中常用的术语 实体&#xff1a;AutoCAD 图元表示 D…

docker安装seata

文章目录 前言准备工作生成seata配置文件创建文件夹创建临时容器拷贝容器内配置文件删除临时容器 导入seata配置到nacos修改application.yml配置文件生成seata所需mysql表修改TC的事务信息存储方式db&#xff08;mysql&#xff09;redis docker指令安装制作docker-compose.yaml…

SAP ERP实施有几个阶段?工博科技带来SAP系统实施项目全流程介绍

根据SAP实施方法论&#xff0c;SAP系统实施流程一共分为五个主要项目阶段&#xff1a;项目准备、蓝图设计、系统实现、上线准备、上线后支持。在项目启动前&#xff0c;双方必须对项目实施过程中各阶段所涉及的任务与交付件以及项目完成标志达成共识&#xff0c;各阶段项目交付…

PCB上的阻抗设计如何变得简单

关于阻抗&#xff08;Impedance&#xff09;&#xff0c;Bob发现很多刚接触到这个概念的小伙伴经常把它与电阻&#xff08;Resistance&#xff09;看作是同等的概念。可能阻抗与电阻按中文名称来说&#xff0c;他们都带一个阻字&#xff0c;而且单位都是Ω&#xff0c;然后阻抗…

代码随想录算法训练营第二十七天|39. 组合总和,40.组合总和II,131.分割回文串

题目&#xff1a;39. 组合总和 给你一个无重复元素 的整数数组 candidates和一个目标整数target&#xff0c;找出 candidates中可以使数字和为目标数target的所有不同组合&#xff0c;并以列表形式返回。你可以按任意顺序返回这些组合。 candidates中的同一个数字可以无限制重复…

RabbitMQ3.13.x之九_Docker中安装RabbitMQ

RabbitMQ3.13.x之_Docker中安装RabbitMQ 文章目录 RabbitMQ3.13.x之_Docker中安装RabbitMQ1. 官网2. 安装1 .拉取镜像2. 运行容器 3. 访问 1. 官网 rabbitmq - Official Image | Docker Hub 2. 安装 1 .拉取镜像 docker pull rabbitmq:3.13.0-management2. 运行容器 # lates…