【LeetCode】 动态规划 刷题训练(三)

这篇具有很好参考价值的文章主要介绍了【LeetCode】 动态规划 刷题训练(三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

931. 下降路径最小和

点击查看:下降路径最小和


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

【LeetCode】 动态规划 刷题训练(三)

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

题目解析

【LeetCode】 动态规划 刷题训练(三)

当处于 (row,col)位置处时,下一行 可以选择 (row+1,col)位置 / (row+1,col-1)位置 /(row+1,col+1)位置处的元素

状态转移方程

dp[i][j]:表示从第一行位置开始到 [i,j]位置处的时候,最小的下降路径

根据最近的一步,划分问题


【LeetCode】 动态规划 刷题训练(三)

[i,j]位置可以由 [i-1,j-1]位置 / [i-1,j]位置 / [ i-1,j+1]位置 向下移动得到

所以可以分为三种情况:


第一种情况:
从 [i-1,j-1]位置 向下移动到到 [i,j] 位置
想要得到[i,j]位置的最小下降路径,就应该先得到[i-1,j-1]位置的最小下降路径 即 dp[i-1,j-1]
再加上[i,j]位置的路径 即 ob[i,j]
第一种情况下 [i,j]位置的最小下降路径为 : dp[i-1,j-1]+ob[i,j]


第二种情况:
从 [i-1,j]位置 向下移动到到 [i,j] 位置
想要得到[i,j]位置的最小下降路径,就应该先得到[i-1,j]位置的最小下降路径 即 dp[i-1,j]
再加上[i,j]位置的路径 即 ob[i,j]
第二种情况下 [i,j]位置的最小下降路径为 : dp[i-1,j]+ob[i,j]


第三种情况:
从 [i-1,j+1]位置 向下移动到到 [i,j] 位置
想要得到[i,j]位置的最小下降路径,就应该先得到[i-1,j+1]位置的最小下降路径 即 dp[i-1,j+1]
再加上[i,j]位置的路径 即 ob[i,j]
第三种情况下 [i,j]位置的最小下降路径为 : dp[i-1,j+1]+ob[i,j]


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

完整代码

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& ob) {
       
       int m=ob.size();
       int n=ob[0].size();
       //dp数组 扩列一行 两列
       //并将 m+1 个 vetcor 数组 的n+2个值 都初始化为正无穷大
       vector<vector<int>>dp(m+1,vector<int>(n+2,INT_MAX));
       //将dp 扩列的第一行初始化为0
      // dp[0].resize(n+2,0);
      int i=0;
       int j=0;
      for(j=0;j<n+2;j++)
      {
          dp[0][j]=0;
      }
       
       for(i=1;i<=m;i++)
       {
           //从[1,1]位置开始到[i,n]位置结束
           for(j=1;j<=n;j++)
           {
               //ob作为原数组,dp作为扩列数组
               //使用dp扩列的下标 寻找ob对应的原数组下标 行需减1 列减1
               dp[i][j]= min(min(dp[i-1][j-1],dp[i-1][j]),dp[i-1][j+1])+ob[i-1][j-1];
           }
       }

     //寻找dp数组的最后一行的最小值
      int minsize=INT_MAX;
      for(j=1;j<=n;j++)
      {
         if(minsize>dp[m][j])
         {
             minsize=dp[m][j];
         }
      } 
     // 返回dp数组的最后一行的最小值
      return minsize;
    }
};

【LeetCode】 动态规划 刷题训练(三)

对于原数组来说,在蓝色区域处使用状态转移方程会发生越界问题,所以通过扩列的方法来解决这个问题


原数组的第一行,只能从当前位置到当前位置,所以储存原始数组元素的值
为了保护影响原数组的第一行的值,所以扩列后的数组第一行 都为0

剩余扩列的位置,若初始化为0,则干扰比较结果,所以为了不影响选取,将其 值 设置为正无穷大


【LeetCode】 动态规划 刷题训练(三)

如:6作为[i,j]位置 ,想要取得最小路径,则向下寻找,理应取到2位置处,
但是由于扩列后出现的0,就会选取0,从而导致结果错误

64. 最小路径和

点击查看:最小路径和


给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。

【LeetCode】 动态规划 刷题训练(三)

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

题目解析

【LeetCode】 动态规划 刷题训练(三)

每次只能向下或者 向右走
从左上角 到右下角 的路径 中 寻找 最小路径和
图中最小路径为: 1+3+1+1+1=7


状态转移方程

dp[i][j] :表示 从起点位置(左上角)到 [i,j]位置 的时候, 此时的最小路径和

根据最近的一步,划分问题


【LeetCode】 动态规划 刷题训练(三)

想要到达[i,j]位置,只能从[i-1,j]位置向下走一步得到
或者 从[i,j-1]位置 向右走一步 得到

所以dp[i][j]划分为两种情况:


第一种从[i-1,j]位置向下得到[i,j]位置

【LeetCode】 动态规划 刷题训练(三)

想要得到[i,j]位置的最小路径 就先需要得到 [i-1,j]位置的最小路径 即dp[i-1,j]
再加上原数组ob 对应[i,j]位置的值 即ob[i,j]
第一种情况 下[i,j]位置的最小路径和为: dp[i-1,j]+ob[i,j]


第二种 从[i,j-1]位置 向右走一步 得到[i,j]位置

【LeetCode】 动态规划 刷题训练(三)

想要得到[i,j]位置的最小路径 就先需要得到 [i,j-1]位置的最小路径 即dp[i,j-1]
再加上原数组ob 对应[i,j]位置的值 即ob[i,j]
第二种情况 下[i,j]位置的最小路径和为: dp[i,j-1]+ob[i,j]


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

完整代码

class Solution {
public:
    int minPathSum(vector<vector<int>>& ob) {
          int m=ob.size();//行
          int n=ob[0].size();//列
          //将m+1个 vector数组 的n+1个值 设置为正无穷大
          //dp数组 将ob原数组 扩一行 和一列
          vector<vector<int>>dp(m+1,vector<int>(n+1,INT_MAX));
          int i=0;
          int j=0;
          //起点位置对应的上一个位置和左一个位置设置为0
          dp[0][1]=0;
          dp[1][0]=0;

          for(i=1;i<=m;i++)
          {
              for(j=1;j<=n;j++)
              {
                  //ob作为原数组 dp作为扩列数组
                  //通过扩列数组的下标 寻找原数组对应的下标 需行减1 列减1
                  dp[i][j]=min(dp[i-1][j],dp[i][j-1])+ob[i-1][j-1];
              }
          }
         // 由于dp是扩列数组 返回右下角 
          return dp[m][n];
          
    }
};

初始化
若使用状态转移方程,则原数组的第一行和第一列都有可能出现越界问题,所以为了避免这个问题,将原数组扩一行和一列

【LeetCode】 动态规划 刷题训练(三)

因为此时并没有上一个位置或者左一个位置,所以dp 数组起点位置(start)的值应为 原数组内对应起点位置的值
为了不影响结果,将start对应的上一个位置和左一个位置都设置为0


【LeetCode】 动态规划 刷题训练(三)

红色区域 的上一个值若设置为0,则会进行状态转移方程时,会取到这个0,干扰结果,
所以为了不影响结果,将其设置为正无穷大


【LeetCode】 动态规划 刷题训练(三)

剩余的位置也同上述一个原因,会干扰结果,所以为了避免影响结果,都设置为正无穷大文章来源地址https://www.toymoban.com/news/detail-498981.html

174. 地下城游戏

点击查看:地下城游戏


恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。
返回确保骑士能够拯救到公主所需的最低初始健康点数。

【LeetCode】 动态规划 刷题训练(三)

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

题目解析

【LeetCode】 动态规划 刷题训练(三)

从左上角 开始 到 右下角 结束
每次只能 向下或者 向右走

-2 -> -3 -> 3 -> 1 -> -5


第一房间时,就会损失2点健康点数,所以骑士想从第一个房间走出来 就需要3点健康点数,但是此时进入第二个房间,还要损失3点健康点数,骑士直接挂掉了 ,所以 初始3点健康点数不可以

将前两个房间走出来,就需要 骑士 起始健康点数为6点(健康点数为0就挂掉了),此时骑士健康点数为1点,
当走完第三个房间时 ,骑士加了3点健康点数,变为4点
当走完第四个房间时 ,骑士加了1点健康点数,变为5点
当走完走到最后一个房间时, 损失5点健康点数 ,骑士健康点数为0,直接挂掉了

所以骑士初始血量应为7点

状态转移方程

因为是通过初始血量判断的,而且不仅受到上面 还有后面的影响
所以要 以某一个位置 为起点 ,来解决问题

dp[i][j] 表示:以[i,j]位置出发,达到终点,存储的值为所需最低初始健康点数

根据最近的一步,划分问题


【LeetCode】 动态规划 刷题训练(三)

[i,j]位置,可以向下走一步达到[i+1,j]位置 或者 向右 走一步 达到 [i,j+1]位置

dp[i][j]分为两种情况:


第一种情况为 从[i,j]位置 向右移动到[i,j+1]位置

【LeetCode】 动态规划 刷题训练(三)

从[i,j]位置走出来 的健康点数 可以保证[i,j+1] 位置 走到终点
即 dp[i][j] +ob[i][j] >= dp[i][j+1]
dp[i][j]>= dp[i][j+1]-ob[i][j]
而dp[i][j]作为最低健康点数,所以 dp[i][j]=dp[i][j+1]-ob[i][j]


第 二 种情况为 从[i,j]位置 向下移动到[i+1,j]位置

【LeetCode】 动态规划 刷题训练(三)

从[i,j]位置走出来 的健康点数 可以保证[i+1,j] 位置 走到终点
dp[i][j] +ob[i][j] >= dp[i+1][j]
dp[i][j]>= dp[i+1][j]-ob[i][j]
而dp[i][j]作为最低健康点数,所以 dp[i][j]=dp[i+1][j]-ob[i][j]


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


若ob[i][j]过大,导致dp[i][j]的值为负数,就不符合要求,因为最低健康点数 为1

dp[i][j]=max(1,dp[i][j]);
若dp[i][j]为负数,就更换为1

完整代码

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& ob) {
      int m=ob.size();
      int n=ob[0].size();
      // 将 m+1个 vector 数组 的 n+1个值 都置为 正无穷大 
      vector<vector<int>>dp(m+1,vector<int>(n+1,INT_MAX));
     
    //从end位置走出来至少剩下1个健康点数
      dp[m-1][n]=1;
      dp[m][n-1]=1;
      int i=0;
      int j=0;
      for(i=m-1;i>=0;i--)
      {
          for(j=n-1;j>=0;j--)
          {
                dp[i][j]=min(dp[i][j+1],dp[i+1][j])-ob[i][j];
                //若dp[i][j]为负,将其置为1
                dp[i][j]=max(1,dp[i][j]);
          }
      }
      //dp[0][0]表示从起点位置开始,到终点至少需要多少初始健康点数
      return dp[0][0];
    }
};

初始化
根据状态转移方程,最后一行和最右行 都会触发越界问题,所以将原数组进行 扩一行 和扩一列

【LeetCode】 动态规划 刷题训练(三)

从end位置才走出来后,一定至少剩下1点健康点数
可能向下走一步,或者向右走一步
从[i,j]位置走出来 的健康点数 可以保证[i,j+1] 位置 走到终点
所以两个位置 都设置为 1


【LeetCode】 动态规划 刷题训练(三)

当前红色区域位置,是需要比较它位置的下一个位置和右一个位置 取其中的小的那个位置,
但是下面的位置是虚拟的,所以不能算上,否则会干扰结果
所以其位置设置为 正无穷大


【LeetCode】 动态规划 刷题训练(三)

剩余的位置也同上述一个原因,会干扰结果,所以为了避免影响结果,都设置为正无穷大

到了这里,关于【LeetCode】 动态规划 刷题训练(三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【LeetCode】动态规划 刷题训练(九)

    点击查看:467. 环绕字符串中唯一的子字符串 定义字符串 base 为一个 “abcdefghijklmnopqrstuvwxyz” 无限环绕的字符串,所以 base 看起来是这样的: “…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd…”. 给你一个字符串 s ,请你统计并返回 s 中有多少 不同非空子串 也在 base 中出现。

    2024年02月15日
    浏览(36)
  • 【Leetcode】动态规划 刷题训练(八)

    点击查看:等差数列划分 如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。 例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。 子数组 是数组中的一个连

    2024年02月11日
    浏览(40)
  • 【LeetCode】动态规划 刷题训练(六)

    点击查看:买卖股票的最佳时机 III 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 示例 1: 输入:p

    2024年02月11日
    浏览(29)
  • LeetCode刷题笔记【30】:动态规划专题-2(不同路径、不同路径 II)

    参考前文 参考文章: LeetCode刷题笔记【29】:动态规划专题-1(斐波那契数、爬楼梯、使用最小花费爬楼梯) LeetCode链接:https://leetcode.cn/problems/unique-paths/description/ 动态规划 : 创建m×n的数组, 对应这个地图, 数组 val 表示 有几种方法可以走到这一格 最开始, 第一行和第一列v

    2024年02月09日
    浏览(60)
  • Leetcode刷题详解——下降路径最小和

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

    2024年02月08日
    浏览(42)
  • 动态规划|【路径问题】|931.下降路径最小和

    目录 题目 题目解析 思路 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 代码 931. 下降路径最小和 给你一个  n x n  的  方形  整数数组  matrix  ,请你找出并返回通过  matrix  的 下降路径   的   最小和  。 下降路径  可以从第一行中的任何元素开始,并从每一

    2024年04月13日
    浏览(44)
  • 【学会动态规划】下降路径最小和(8)

    目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 学习一个算法没有捷径,更何况是学习动态规划, 跟我一起刷动态规划算法题,一起学会动态规划! 题目链接:931. 下降路径最小和 - 力扣(

    2024年02月16日
    浏览(40)
  • 【动态规划上分复盘】下降路径最小和|礼物的最大价值

    本文主要讲述动态规划思路的下降路径最小和以及礼物的最大价值两道题。 1.确定状态表示(确定dp数组的含义) 2.确定状态转移方程(确定dp的递推公式) 3.确定如何初始化(初始化要保证填表正确) 4.确定遍历顺序 5.返回值 点我直达 1.确定状态表示,即确定dp数组的含义。

    2024年02月12日
    浏览(39)
  • 刷题之动态规划-路径问题

    大家好,我是jiantaoyab,开始刷动态规划的题目了,要特别注意初始化的时候给什么值。 动态规划5个步骤 状态表示 :dp数组中每一个下标对应值的含义是什么- dp[i]表示什么 状态转移方程: dp[i] 等于什么 1 和 2 是动态规划的核心步骤,第三步是初始化,保证填表的时候不越界

    2024年04月13日
    浏览(30)
  • 《动态规划》刷题训练

    你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统, 如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动

    2024年01月19日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包