动态规划-路径问题

news2024/11/16 19:41:34

不同路径(medium)

题目链接:

62. 不同路径

题目描述:

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?

示例 1:

image-20230829140720209

输入:m = 3, n = 7
输出:28

题目解析

机器人在左上角,我们可以向下走一格或者向右走一格,问一问我们有多少路径可以走到右下角.

image-20230829141232228

这里要注意的是,我们求得是路径数.

算法原理

状态表示

按照经验,我们以…为结尾表示状态.

dp[i][j]: 表示我们到达下标为[i,j]位置的总共的路径数.

状态转移方程

我们向一下,怎么可以到达[i,j]位置,可以很容易的想到,我们[i-1,j]向下走一格,或者是[i,j-1]向右走一格.由于我们求得是路径数,那么此时状态方程为dp[i][j] = dp[i-1][j] + dp[i][j-1].

初始化

这里用的i-1和j-1,所以我们这里加上辅助接点.加上辅助接点需要注意是我们下标对真实数组下标的映射.

image-20230829142330131

为了使dp[1][1]数据有效,我们这里让dp[0][1] = 1 && dp[1][0] = 0或者dp[0][1] = 0 && dp[1][0] = 1就可以了.

填表顺序

和前面一样从左先右,大方向从上向下.

返回值

返回dp[n][m]

编写代码

class Solution
{
public:
  int uniquePaths(int m, int n)
  {
    // 参数检测
    std::vector<std::vector<int>> dp(m + 1, std::vector<int>(n + 1, 0));
    // dp[0][1] = 1;
    dp[1][0] = 1;
    for (size_t i = 1; i <= m; i++)
    {
      for (size_t j = 1; j <= n; j++)
      {
        dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
      }
    }

    return dp[m][n];
  }
};

image-20230829142733125

不同路径II(medium)

题目链接:

63. 不同路径 II

题目描述:

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

示例1:

image-20230829142923917

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

题目解析

和上面一样,只不过我们这里有障碍物,存在障碍物的路径是不作数的.

算法原理

状态表示

经验,dp[i][j]表示到达[i,j]位置的总路径数.

状态转移方程

这里有障碍物,首先我们要判断[i,j]是不是障碍物.

image-20230829143440176

初始化

和上面一样.

填表顺序

从左先右.

返回值

返回dp[n][m]

编写代码

class Solution
{
public:
  int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid)
  {
    // 参数判断
    int n = obstacleGrid.size();
    int m = obstacleGrid.back().size();
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(m + 1, 0));
    dp[0][1] = 1;

    for (size_t i = 1; i <= n; i++)
    {
      for (size_t j = 1; j <= m; j++)
      {
        if (obstacleGrid[i - 1][j - 1] == 0)
          dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
      }
    }
    return dp[n][m];
  }
};

image-20230829144839780

礼物的最大价值(medium)

题目链接:

剑指 Offer 47. 礼物的最大价值

题目描述:

在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

示例 1:

输入: 
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物

题目解析

我们从左上角跳到右下角的过程中,每个格子都有礼物,到达一个格子就可以得到这个礼物.求我们这个过程中我们可以得到礼物的最大价值.

算法原理

状态表示

题目+经验.dp[i][j]:表示到达[i,j]位置我们得到最大价值的价值数.

状态转移方程

可以先上面和左面到达[i,j]位置,但是这两个情况我们只能选择一种,那么此时选择最大价值的一种dp[i][j] = max(dp[i-1][j], dp[i][j-1])+value[i][j]

初始化

这里也加上一个辅助行和列.

填表顺序

从左先右.

返回值

返回dp[n][m]

编写代码

class Solution
{
public:
  int maxValue(vector<vector<int>> &grid)
  {
    int n = grid.size();
    int m = grid.back().size();
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(m + 1, 0));
    for (size_t i = 1; i <= n; i++)
    {
      for (size_t j = 1; j <= m; j++)
      {

        dp[i][j] = std::max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
      }
    }
    return dp[n][m];
  }
};

image-20230829150718447

下降路径最小和(medium)

题目链接:

[931. 下降路径最小和](https://leetcode.cn/problems/three-steps-problem-lcci/)

题目描述:

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

示例 1:

img

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

题目解析

很简单,我们可以通过三种方式到达x位置处.

image-20230829151045510

题目上求从第一行的任意位置通过规则走到最后一行,求我们的和最小.

算法原理

状态表示

dp[i][j]: 以[i,j]位置为结尾,我们的最小的路径和

状态转移方程

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

初始化

我们这里要求了i-1和j-1已经j+1,此时我们这么添加辅助的.

image-20230829151646649

对于x这一行,他依赖上面的三个,所以第一行必须是0.对于y这一列,以y来举例子.我们发现y这一个,我们发现它依赖x这个数,所以x左侧的数据一定要被抛弃,那么我们初始化值大点.

填表顺序

上->下,左->右

返回值

我们求到达最后一行的最小路径和,所以要遍历一遍.

编写代码

class Solution
{
public:
  int minFallingPathSum(vector<vector<int>> &matrix)
  {
    int n = matrix.size();
    int m = matrix.back().size();
    std::vector<std::vector<long long>> dp(n + 1, std::vector<long long>(m + 2,INT_MAX));
    for (size_t i = 0; i <= m; i++)
    {
      dp[0][i] = 0;
    }
    for (size_t i = 1; i <= n; i++)
    {
      for (size_t j = 1; j <= m; j++)
      {
        dp[i][j] = (long long)(std::min(dp[i - 1][j], std::min(dp[i - 1][j + 1], dp[i - 1][j - 1])) + (long long)matrix[i - 1][j - 1]);
      }
    }
    long long minVal = dp[n][0];
    for (size_t i = 1; i <= m; i++)
    {
      minVal = std::min(minVal, dp[n][i]);
    }
    return minVal;
  }
};

image-20230829153336207

最小路径和(medium)

题目链接:

64. 最小路径和

题目描述:

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

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

示例 1:

img

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

题目解析

这个比上面那个简单.

算法原理

状态表示

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

状态转移方程

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

初始化

只需要保证dp[0][1] = 0

image-20230829153728839

填表顺序

从左先右.

返回值

return dp[n][m];

编写代码

class Solution
{
public:
  int minPathSum(vector<vector<int>> &grid)
  {
    int n = grid.size();
    int m = grid.back().size();
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(m + 1, INT_MAX));
    dp[0][1] = 0;
    for (size_t i = 1; i <= n; i++)
    {
      for (size_t j = 1; j <= m; j++)
      {
        dp[i][j] = std::min(dp[i][j - 1], dp[i - 1][j]) + grid[i - 1][j - 1];
      }
    }
    return dp[n][m];
  }
};

image-20230829154118846

地下城游戏(hard)

题目链接:

174. 地下城游戏

题目描述:

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

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

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

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

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

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

示例 1:

img

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

题目解析

勇士通过走路的规则,我们有最少多少血可以走到右下角.

算法原理

状态表示

继续按照上面的思想来.

以 … 为结尾.dp[i][j]: 以[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])

初始化

这里留给大家.

填表顺序

右->左,下->上

返回值

题目要求给定一个n,求到达第n个台阶的方法数,这里就是dp[n]

编写代码

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

image-20230829154943260

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

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

相关文章

博流RISC-V芯片Eclipse环境搭建

文章目录 1、下载 Eclipse2、导入 bouffalo_sdk3、编译4、烧录5、使用ninja编译 之前编译是通过 VSCode 编译&#xff0c;通过手工输入 make 命令编译&#xff0c;我们也可以通过 Eclipse 可视化 IDE 来编译、烧录。 1、下载 Eclipse 至 Eclipse 官网 https://www.eclipse.org…

【JavaSE专栏91】Java如何主动发起Http、Https请求?

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;3年JAVA全栈开发经验&#xff0c;专注JAVA技术、系统定制、远程指导&#xff0c;致力于企业数字化转型&#xff0c;CSDN学院、蓝桥云课认证讲师。 主打方向&#xff1a;Vue、SpringBoot、微信小程序 本文讲解了如何使用…

VMware标准虚拟交换机和分布式交换机

一、虚拟交换机 初期的网络虚拟化&#xff0c;是非常狭义的概念&#xff0c;主要指的是因为计算资源虚拟化&#xff0c;每台物理宿主机上安装了虚拟化软件&#xff0c;同时会部署了虚拟交换机&#xff0c;负责物理机上面承载的VM&#xff08;虚拟机&#xff09;之间与对外的通…

【Rust日报】2023-08-28 WASM 微运行时与 Rust

WASM 微运行时与 Rust 传统上&#xff0c;微控制器只能运行 C 代码。固件开发人员通常会使用 Eclipse 基于 IDE 以及定制的编译器工具链来编译代码。但是&#xff0c;MicroPython 最近变得流行起来。RaspberryPi Pico、ExpressIf 的 ESP32 是一些对 MicroPython 支持相当不错的…

直流电源开关TMI6240I/6250I——解决分立MOS开关易失效,安全更可靠

互联网时代带动了电子产品行业的发展&#xff0c;人们对电子产品的需求越来越高&#xff0c;TV、显示器、笔记本、智能家居、平板等产品只增不减&#xff0c;为生活提供了极大的便利。与此同时&#xff0c;随着拥有的电子产品增多也带来了不少”烦恼“——产品越多&#xff0c;…

标杆项目,获奖!

近日&#xff0c;第二届“光华杯”千兆光网应用创新大赛东部大区赛决赛在上海举行。天翼物联、南京港华燃气联合申报的“千兆光网融物赋智&#xff0c;赋能大型城市燃气安全及智慧运营”项目荣获三等奖并晋级全国总决赛。 今年以来&#xff0c;中国信息通信研究院联合中国通信标…

基于RabbitMQ的模拟消息队列之二---创建项目及核心类

一、创建项目 创建一个SpringBoot项目&#xff0c;环境&#xff1a;JDK8&#xff0c;添加依赖&#xff1a;Spring Web、MyBatis FrameWork(最主要&#xff09; 二、创建核心类 1.项目分层 2.核心类 在mqserver包中添加一个包&#xff0c;名字为core&#xff0c;表示核心类…

2023最新Python重点知识万字汇总

这是一份来自于 SegmentFault 上的开发者 二十一 总结的 Python 重点。由于总结了太多的东西&#xff0c;所以篇幅有点长&#xff0c;这也是作者"缝缝补补"总结了好久的东西。 **Py2 VS Py3** * print成为了函数&#xff0c;python2是关键字* 不再有unicode对象…

赢得明星代言:邀请明星成为品牌代言人的步骤与注意事项

在品牌推广和营销中&#xff0c;与明星合作做代言人是一种常见的策略&#xff0c;可以有效地提升品牌知名度和形象。然而&#xff0c;找明星做代言人并不是一件轻松的事情&#xff0c;需要慎重考虑和策划。媒介易拥有3000多位一二线明星合作资源&#xff0c;为您提供专业的明星…

基于java+springboot+vue的简历系统

​ 系统介绍&#xff1a; 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;简历系统当然也不能排除在外。简历系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方…

基于Java的基数排序(详述)

基于Java的基数排序&#xff08;详述&#xff09; 原理介绍Java实现文献参考 原理介绍 一、什么是基数排序 &#xff08;1&#xff09;通过键值得各个位的值&#xff0c;将要排序的元素分配至一些桶中&#xff0c;达到排序的作用 &#xff08;2&#xff09;基数排序法是属于稳…

Mybatis1.3 查询详情

1.3 查询详情 1.3.1 编写接口方法1.3.2 编写SQL语句1.3.3 编写测试方法1.3.4 参数占位符1.3.5 parameterType使用1.3.6 SQL语句中特殊字段处理 有些数据的属性比较多&#xff0c;在页面表格中无法全部实现&#xff0c;而只会显示部分&#xff0c;而其他属性数据的查询可以通过 …

常用免费 API 接口推荐与分享,收藏备用

写在最前 各类免费 API 接口整理&#xff0c;主要是 LuckyCola上和其他各类开放平台上的一些&#xff0c;有需要的赶紧收藏备用。 一、LuckyCola免费api系列: 官网地址:LuckyCola 免费图床 | 智能对话机器人AI | 网站监控与免费API费图床是一款提供高质量图片上传与分享的平…

风丘方案助力车企升级 解决“国六”标准新难题

一 背景 尾气排放指标是衡量汽车质量和品质的主要指标之一&#xff0c;且汽车的尾气排放必须达到相应的标准才准许出厂&#xff0c;因此&#xff0c;对汽车排放的尾气进行检测是汽车生产过程的重要环节。汽车尾气检测过程是在排放实验室里进行的&#xff0c;这需要模拟汽车实际…

MySQL8.0.30一主两从复制与配置(一)

MySQL8.0.30一主两从复制与配置(一)_蜗牛杨哥的博客-CSDN博客 MySQL8.xx一主两从复制安装与配置 MySQL8.XX随未生成随机密码解决方案 本文主要对: MySQL8.xx安装与配置 的完善与补充 一: 搭建环境 主机IP 端口 节点备注192.168.1.100 …

Gazebo打不开,报错process has died[pid 7798, exit code1]解决办法

Gazebo打不开&#xff0c;报错process has died[pid 7798, exit code1]&#xff0c;如下图所示&#xff1a; 原因&#xff1a;可能是由于有gazebo进程没有终止&#xff0c;所以无法打开。 解决办法&#xff1a;依次执行下面两个命令 killall gzserver killall gzclient问题解…

算法通关村-----位运算的规则

1 数字在计算机中的表示 机器数&#xff1a;一个数在计算机中的二进制表示 真值&#xff1a;带符号位的机器数对应的真正数值 机器数可分为原码、反码和补码。 原码&#xff1a;符号位加上真值的绝对值 反码&#xff1a;正数的反码是其本身&#xff0c;负数的反码的在其原…

基于ssm医院在线挂号预约系统源码和论文

基于ssm医院在线挂号预约系统源码和论文072 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 课题研究的目的及意义&#xff1a; 专家号难求&#xff0c;是医院现场挂号存在的主要问题之一&#xff0c;每一名专…

【算法专题突破】双指针 - 有效三角形的个数(5)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;611. 有效三角形的个数 - 力扣&#xff08;Leetcode&#xff09; 我们可以根据示例1来理解这一道题目&#xff0c; 他说数组里面的数可以组成三角形三条边的个数&#x…

maven的依赖下载不下来的几种解决方法

前言 每次部署测试环境&#xff0c;从代码库拉取代码&#xff0c;都会出现缺少包的情况。然后找开发一通调试&#xff0c;到处拷包。 方案一&#xff1a;pom文件注释/取消注释 注释掉pom.xml里的报红色的依赖&#xff08;同时可以把本地maven库repo里对应的包删除&#xff09;&…