[动态规划]---part2

前言

作者:小蜗牛向前冲

专栏小蜗牛算法之路

 专栏介绍:"蜗牛之道,攀登大厂高峰,让我们携手学习算法。在这个专栏中,将涵盖动态规划、贪心算法、回溯等高阶技巧,不定期为你奉上基础数据结构的精彩算法之旅。一同努力,追逐技术的星辰大海。"

 

目录

一、不同路径II(medium)

a、解题思路 

b、代码

二、礼物的最⼤价值(medium)

a、解题思路 

b、代码

三、 下降路径最⼩和(medium)

a、解题思路 

b、代码

四、 最⼩路径和(medium)

a、解题思路 

b、代码

五、地下城游戏(hard) 

a、解题思路 

b、代码


本期:继续手撕动态规划:不同路径II(medium),礼物的最⼤价值(medium),下降路径最⼩和(medium),最⼩路径和(medium),地下城游戏(hard)

继续刷动态规划相关算法题,如果不清楚什么是动态规划的可以看这里:[动态规划]---part1

一、不同路径II(medium)

一个机器人位于一个 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
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {

    }
};

a、解题思路 

这道题和同路径I的解题思路非常相似,但是就是在机器人找 到终点的过程中,会有障碍物。

1、转态表示

首先我们想以i,j位置为结尾表示什么

dp[i][j表示:以i,j位置结尾的时候,机器人到这里有多少条路径

 2、状态转移方程

根据最近的一个位置划分:

当前位置有障碍物:

返回0

当前位置没有障碍物:

dp[i][j] = dp[i-1][j]+dp[i][j-1];

大家可能会想,我要是在[i-1][j]或者[i][j-1]遇到障碍物了,状态转态方程还可以相加吗?

其实是可能的,因为我在遇到障碍物是返回0的,而0对相加的结果是没有影响的。 

3、初始化

这里我们要初始化,就是在二维数组多开一行和一列,但我们要思路多开的行列填什么呢(一切都是为了填表走服务)?,很明显,机器人是在[1,1]位置开始走的,也就说[1,1]位置肯定要为1(当最特色情况起点就是中点),所以我们只要保证,dp[1][0]==1或者dp[0][1]==1即可。其他位置看情况决定。

这里除了要注意填表的初始化,还要注意下标映射关心的改变:

 obstacleGrid[0][0]-------->映射dp[1][1];

 obstacleGrid[2][3]-------->映射dp[3][4];

也就是横着纵坐标都要加1

4、 填表顺序

从上往下填写每一行,每一行都是从左往又开始填写 

5、返回值

dp[m][n]

b、代码

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
    {
        int m = obstacleGrid.size();//有多少行
        int n = obstacleGrid[0].size();//有多少列

        //创建dp表
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));

        //初始化
        dp[1][0] = 1;

        //填表
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (obstacleGrid[i - 1][j - 1] == 1)
                {
                    dp[i][j] = 0;
                }
                else
                {
                    dp[i][j] = dp[i][j - 1] + dp[i-1][j];
                }
            }
        }

        //返回
        return dp[m][n];

    }
};

 Leetcode 测试结果:   

二、礼物的最⼤价值(medium)

现有一个记作二维矩阵 frame 的珠宝架,其中 frame[i][j] 为该位置珠宝的价值。拿取珠宝的规则为:

  • 只能从架子的左上角开始拿珠宝
  • 每次可以移动到右侧或下侧的相邻位置
  • 到达珠宝架子的右下角时,停止拿取

注意:珠宝的价值都是大于 0 的。除非这个架子上没有任何珠宝,比如 frame = [[0]]

示例 1:

输入: frame = [[1,3,1],[1,5,1],[4,2,1]]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最高价值的珠宝

提示:

  • 0 < frame.length <= 200
  • 0 < frame[0].length <= 200

class Solution {
public:
    int jewelleryValue(vector<vector<int>>& frame) {

    }
};

a、解题思路 

这种路径题目极大可能用动态规划求解

1、转态表示

首先我们想以i,j位置为结尾表示什么

dp[i][j表示:以i,j位置结尾的时候,此时礼物的最大值

 2、状态转移方程

根据最近的一个位置划分:

从[i-1][j]------>[i][j]:

那礼物的不就是dp[i-1][j]+frmae[i-1][j-1];(frmae的坐标是映射过的)

从[i][jj-1]------>[i][j]:

那礼物的不就是dp[i][j-1]+frmae[i-1][j-1];

但是我们要求的是拿到礼物的最大值:

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

3、初始化

这里的初始化就非常简单了,对应[1][1]位置我们肯定是要保证他在填表的时候不变的,那么[1][0]和[0][1]位置肯定是0,至于0行,0列后面的,按理来说是要初始化为负无穷的,但因为礼物值>=0,所以初始化为0也可以。(这里就不用我们初始化了,因为vector是有初始化功能的)

4、 填表顺序

从上往下填写每一行,每一行都是从左往又开始填写 

5、返回值

dp[m][n]

b、代码

class Solution {
public:
    int jewelleryValue(vector<vector<int>>& frame)
    {
        int m = frame.size();//行
        int n = frame[0].size();//列

        //创建dp表
        vector<vector<int>> dp(m+1,vector<int>(n+1));

        //初始化,vector已经完成

        //填表
        for(int i = 1;i<=m;i++)
        {
            for(int j = 1;j<=n;j++)
            {
                dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + frame[i-1][j-1];
            }
        }
        return dp[m][n];

    }
};

  Leetcode 测试结果:  

三、 下降路径最⼩和(medium)

给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径  最小和 。

下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)(row + 1, col) 或者 (row + 1, col + 1) 。

示例 1:

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

示例 2:

输入:matrix = [[-19,57],[-40,-5]]
输出:-59
解释:如图所示,为和最小的下降路径

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 100
  • -100 <= matrix[i][j] <= 100
class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {

    }
};

 

a、解题思路 

上面我们刚刚做完最大价值,现在来做最小和,二者思路非常相似,但是我们这里要仔细读题。

1、转态表示

dp[i][j]表示:到达[i,j]位置时,最小的下降路径

 2、状态转移方程

根据最近的一个位置划分:

从[i-1][j-1]------>[i][j]:

那最小的下降路径不就是dp[i-1][j-1]+m[i][j;

从[i][jj-1]------>[i][j]:

那最小的下降路径不就是dp[i-1][j]+m[i][j;

从[i]-1[jj]------>[i][j]:

那最小的下降路径不就是dp[i-1][j+1]+m[i][j;

 

但是我们要求的是最小的下降路径

 状态转移方程:dp[i][jj = min(x,y,z)+m[i][j];

3、初始化

这里的初始化和前面有点不同,所以我希望大家在做这种类型题目的时候,不要无脑初始化,一定要先进行分析。

  • 首先我们肯定是其想是第一行位置的值, 肯定是其本身(最小的下降路径),根据转态转移方程,我们肯定是不能让我们新添加的行影响结果,所以把第一行初始化为0
  • 在选择dp[1][2]进行观测(不一定非要选择这个位置,合适就好),根据转态转移方程,我们肯定是不能让我们新添加的列影响结果,所以要把第一列初始化为正无穷(第一行元素除外)
  • 在选择dp[1][3]进行观察,,根据转态转移方程,我们肯定是不能让我们新添加的列影响结果所以要把最后一列初始化为正无穷(第一行元素除外)

4、 填表顺序

从上往下填写,值到最后一行

5、返回值

返回最后一行的最小值

b、代码

class Solution {
public:
    int get_min(int x,int y,int z)
    {
        int tmp = min(x,y);
        return min(tmp,z);
    }
    int minFallingPathSum(vector<vector<int>>& matrix)
    {
        int m = matrix.size();
        int n = matrix[0].size();

        int max = INT_MAX;//相当与正无穷
        //创建dp表
        vector<vector<int>> dp(m+1,vector<int>(n+2,max));

        //初始化 这里初始化第一行就好
        for(int i = 0;i<n+2;i++)
        {
            dp[0][i] = 0;
        }

        //填表
        for(int i = 1;i<=m;i++)
        {
            for(int j =1;j<=n;j++)
            {
                dp[i][j] = get_min(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+matrix[i-1][j-1];
            }
        }
        //遍历最后一行找出最小值返回
        int min = max;
        for(int i = 1;i<=n;i++)
        {
            if(dp[m][i]<min) min = dp[m][i];

        }
        return min;
    }
};

  Leetcode 测试结果:   

四、 最⼩路径和(medium)

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例 1:

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

示例 2:

输入:grid = [[1,2,3],[4,5,6]]
输出:12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 200
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {

    }
};

a、解题思路 

又是这种路径的问题,我相信如果大家,认真做了前面的题,这题思路就非常清晰了

1、转态表示

dp[i][j]表示:到达[i,j]位置时,最小的路径路径和

 2、状态转移方程

根据最近的一个位置划分:

从[i-1][j]------>[i][j]:

那最小路径和不就是dp[i-1][j]+g[i][j];

从[i][jj-1]------>[i][j]:

那最小的下降路径不就是dp[i][j-1]+g[i][j];

但是我们要求的是最小的下降路径

 状态转移方程: dp[i][j] = min(dp[i-1][j],dp[i][j-1])+grid[i-1][j-1];

3、初始化

还先分析第一个位置,那么dp[0][1]和dp[1][0]就要初始化为0,其他位置,我们想现在可以总结一下了:

  • 当求最小值    就初始化为正无尽
  • 当求最大值   就初始化为负无尽

4、 填表顺序

从上往下填写,在从左往右。

5、返回值

dp[m][n]

b、代码

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid)
    {
        int m = grid.size();
        int n = grid[0].size();

        //创建dp
          vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));
        //初始化
        dp[1][0] = dp[0][1] = 0;

        //填表
        for(int i = 1;i<=m;i++)
        {
            for(int j = 1;j<=n;j++)
            {
                dp[i][j] = min(dp[i-1][j],dp[i][j-1])+grid[i-1][j-1];
            }
        }
        
        //返回
        return dp[m][n];
    }
};

  Leetcode 测试结果:    

 

五、地下城游戏(hard) 

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

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。

返回确保骑士能够拯救到公主所需的最低初始健康点数。

注意:任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

示例 1:

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

示例 2:

输入:dungeon = [[0]]
输出:1

 

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {

    }
};

a、解题思路 

大家遇到这种文字多的题目,不要害怕,如果读不明白,就带这例题求推就好了。

1、转态表示

大家可能非常想到是以某一个位置结尾推出: 

dp[i][j]表示:到达[i,j]位置时,所需的最低血量点数。但这是不正确的,因为我们不仅仅在[i][j]位置受到前面位置的影响,其实我们还会受到后面位置的影响,所以这样的转态表示是不可取的。

但是我们还可以想 一下以某位置为起点来推

dp[i][j]表示从[i,j]位置重出发,到达终点所要的最低健康血量

 2、状态转移方程

根据最近的一个位置划分:

往右走那最低血量应该是:dp[i][j+1] -d[i][j]

往下走那最低血量应该是:dp[i]+1[j] -d[i][j]

但是我们还要注意当d[i][j]此时非常大的时候,dp[i][j]可能出现负值,但是这样是不符合常理的,所以我们要处理一下:dp[i][j] = max(1,dp[i][j]);

,到达终点所要的最低健康血量

 状态转移方程: dp[i][j] = min(dp[i][j+1],dp[i+1][j])+d[i][j];

3、初始化

这里我们填表因为是从后往前面填的,所以我们要关注最后一个位置,当我们救出公主的时候,肯定要保证自己的血量不为0,所以在[m][n-1]和[m-1][n]位置填1就好,其他位置为不影响 状态转移方程应该都初始化为正无穷。

4、 填表顺序

从下往上填写,在从右往左。

5、返回值

dp[0][0]

b、代码

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];
    }
};

   Leetcode 测试结果:  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python基础第二天

世界杯小组赛成绩 注意&#xff1a; 1.循环 1.1while 1.2for 1.3 range 1.4 while else while 循环正常执行完才能执行else语句

算法竞赛基础:树状数组

算法竞赛基础&#xff1a;树状数组 是什么&#xff1f; 树状数组虽然语义上是树状&#xff0c;但是实际上还是一个数组。 树状数组的功能就是单点和区间的修改和查询。 例如&#xff0c;如果想增加一个点的值&#xff0c;那么你需要让其上方所有能对齐的树状数组c全部增加相同…

流畅的Python(十七)-使用future处理并发

一、核心要义 主要以三个模拟网络下载的代码-分别是依序下载、使用concurrent.futures模块中的Executor.map方法、以及使用该模块的executor.submit和futures.as_completed方法&#xff0c;来展示Python实现并发编程的其中一种方式。 二、代码示例 1、依序下载的脚本 #!/us…

JS数组,if等结构语序

目录 浏览器的断点调试&#xff1a; 流程控制&#xff1a; 顺序流程控制&#xff1a;流程代码会逐行向下进行。 分支流程控制&#xff1a; IF语句&#xff1a; Switch语句&#xff1a; Switch和if的区别&#xff1a; 三元表达式&#xff1a; 循环&#xff1a; for循环…

XSS漏洞--概念、类型、实战--分析与详解[结合靶场pikachu]

目录 一、XSS概念简述 1、XSS简介&#xff1a; 2、XSS基本原理&#xff1a; 3、XSS攻击流程&#xff1a; 4、XSS漏洞危害&#xff1a; 二、XSS类型&#xff1a; 1、反射型XSS&#xff1a; 2、存储型XSS&#xff1a; 3、DOM型XSS&#xff1a; 三、靶场漏洞复现(pikach…

数据结构之顺序表及其实现!

目录 ​编辑 1. 顺序表的概念及结构 2. 接口的实现 2.1 顺序表的初始化 2.2 检查顺序表容量是否已满 2.3 顺序表的尾插 ​编辑 2.4 顺序表的尾删 2.5 顺序表的头插 2.6 顺序表的头删 2.7 顺序表在pos位置插入 2.8 顺序表在pos位置删除 2.9 顺序表的查找 2.10 顺…

喜报|3DCAT成为国内首批适配Vision Pro内容开发者

近日&#xff0c;苹果在上海总部举办了国内首场 Apple Vision Pro 开发者实验室活动&#xff0c;3DCAT作为国内领先的实时渲染云平台参与了此次活动&#xff0c;成为国内首批适配 Vision Pro 的内容开发者之一。 Vision Pro是苹果于2023年6月发布的首个空间计算设备&#xff0…

Vue+SpringBoot打造超市账单管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统设计3.1 总体设计3.2 前端设计3.3 后端设计在这里插入图片描述 四、系统展示五、核心代码5.1 查询供应商5.2 查询商品5.3 新增超市账单5.4 编辑超市账单5.5 查询超市账单 六、免责说明 一、摘要 1.1 项目介绍 基于…

Redis的三种集群模式(图解)

主从复制模式 一个主节点和多个从节点。主节点提供写入和读取功能&#xff0c;但是从属节点只提供读取功能。 主从复制的数据同步过程如下&#xff1a; &#xff08;1&#xff09;首先主节点启动&#xff0c;然后从属节点启动&#xff0c;从属节点会连接主节点并发送SYNC命令以…

JAVA WEB案例-登录校验-日志记录

一 前言 在现代社会中&#xff0c;随着互联网的快速发展&#xff0c;WEB应用的安全性问题变得越来越突出。作为一名程序员&#xff0c;我们不仅要注重WEB应用的功能实现&#xff0c;还需要重视安全性问题。在实际开发中&#xff0c;登录校验是非常重要的安全措施&#xff0c;能…

element-ui配置

全局配置 完整引入 Element&#xff1a; import Vue from vue; import Element from element-ui; Vue.use(Element, { size: small, zIndex: 3000 });按需引入 Element Vue.prototype.$ELEMENT { size: small, zIndex: 3000 };如果是vue.config.js中配置了externals 使用按…

【论文精读】Attention Bottlenecks for Multimodal Fusion 视频分类任务

本文并非逐句翻译&#xff0c;添加个人理解与疑惑&#xff0c;如有需要&#xff0c;请自行阅读原文。 Attention Bottlenecks for Multimodal Fusion 多模态融合的注意力瓶颈 会议&#xff1a;NIPS2021 Benchmark&#xff1a;Audioset、Epic Kitchens和VGGSound等 Backbone&…

数组常见算法

一、数组排序 冒泡排序 本篇我们介绍最基本的排序方法&#xff1a;冒泡排序。 实现步骤 1、比较两个相邻元素&#xff0c;如果第一个比第二个大&#xff0c;就交换位置 2、对每一对相邻元素进行同样的操作&#xff0c;除了最后一个元素 特点 每一轮循环后都会把最大的一个…

2024/3/6打卡最短编辑距离---线性DP

题目&#xff1a; 给定两个字符串 A 和 B&#xff0c;现在要将 A 经过若干操作变为 B&#xff0c;可进行的操作有&#xff1a; 删除–将字符串 A 中的某个字符删除。插入–在字符串 A 的某个位置插入某个字符。替换–将字符串 A 中的某个字符替换为另一个字符。 现在请你求出&a…

蓝桥杯练习题——前缀和

1.壁画 思路 1.求最坏情况下&#xff0c;画的墙总和是多少 2.画的墙在中间连续一段&#xff0c;画了的墙长度是 n / 2 向上取整 3.取最大的 n / 2 向上取整区间和 #include<iostream> using namespace std; const int N 5e6 10; char s[N]; int a[N]; int t, n;int m…

重磅:2024广州国际酒店工程照明展览会

2024广州国际酒店工程照明展览会 Guangzhou international hotel engineering lighting exhibition 2024 时间&#xff1a;2024年12月19-21日 地点&#xff1a;广州.中国进出口商品交易会展馆 承办单位&#xff1a;广州佛兴英耀展览服务有限公司 上海昶文展览服务有限公司…

【详识C语言】自定义类型之二:枚举

本章重点 枚举 枚举类型的定义 枚举的优点 枚举的使用 枚举 枚举顾名思义就是一一列举。 把可能的取值一一列举。 比如我们现实生活中&#xff1a; 一周的星期一到星期日是有限的7天&#xff0c;可以一一列举。 性别有&#xff1a;男、女、保密&#xff0c;也可以一一列举。…

【深度学习笔记】5_8 网络中的网络NiN

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 5.8 网络中的网络&#xff08;NiN&#xff09; 前几节介绍的LeNet、AlexNet和VGG在设计上的共同之处是&#xff1a;先以由卷积层构成的…

Vue.js+SpringBoot开发森林火灾预警系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 系统基础模块2.3 烟雾传感器模块2.4 温度传感器模块2.5 历史记录模块2.6 园区数据模块 三、系统设计3.1 用例设计3.1.1 森林园区基础系统用例设计3.1.2 森林预警数据用例设计 3.2 数据库设计3.2.1 烟雾…

[PyQt5]PyQt5连接MYSQL时显示Driver not loaded解决方案

在第一次用PyQt5的 QSqlDatabase.addDatabase 连接mysql的时候&#xff0c;可能会出现Driver not loaded的情况&#xff0c;如下&#xff1a; from PyQt5.QtSql import QSqlQuery, QSqlDatabase from PyQt5.QtWidgets import QApplication import sysapp QApplication(sys.ar…