当前位置: 首页 > news >正文

代码随想录算法训练营第60期第三十六天打卡

        大家好!今天我们就会正式进入动态规划的章节,以前我们相继学完了回溯算法,贪心算法,今天的动态规划应该是相当重要同时也是相当难的章节,那我们废话不多说直接进入我们今天的章节。

第一部分 动态规划理论基础

       那究竟什么是动态规划,如何使用动态规划算法来解决实际的题目,它会不会与贪心算法一样没有固定的模板,还有大家在动态规划里面看到的dp数组究竟是用来做什么的,带着这些疑问我们开始动态规划的理论基础章节。

       动态规划中每一个状态一定是由上一个状态推导出来的,这点很重要,这里也区分贪心算法,我们的贪心算法是局部最优退出全局最优,我们接触动态规划的第一个重要问题就是背包问题,那什么是背包问题,就比如说有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。那这时候我们的dp数组就起作用了,动态规划中dp[j]是由dp[j-weight[i]]推导出来的,然后取max(dp[j], dp[j - weight[i]] + value[i])。这个强调的是状态转移,同时我们知道dp[i]数组的含义就是前i件物品的最大价值,它表示的就是最大价值,因此这或许就是我们最后的结果,这个最大值是存在于我究竟选不选第j件物品,选的话就是dp[j - weight[i]] + value[i],不选的话就是dp[j],以后到了背包问题的时候会再详细给大家讲。

        接下来是我们的解题步骤,

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

       这个我就不废话了,这个叫做动归五部曲,每一道题目我们都要按照这个思路去想,这个很重要,尤其是初始化很重要大家务必根据题目要求准确初始化。

       还有一个问题就是关于debug的问题,其实就主要说一点,大家可以去一个编译器去打印dp数组,看看我们的dp数组是否正确,如果发现不正确我们就需要考虑我们找到的状态转移方程与初始化是否正确,关于理论基础我就说这么多,接下来我们就进入例题详细看看如何使用动规五部曲来解决实际的问题。

第一题对应力扣编号为509的题目斐波纳契数

       这一道题目想必大家在入门递归的时候应该接触过,因为这道题目本就可以使用递归解决,不过我们了解递归算法的时间复杂度是指数级别的很慢,如果提交这道题目大概率会超时的,因此我们就可以考虑我们今天的动态规划来解决,首先根据动规五部曲,dp[i]表示的就是第i项的具体值了,但是我们差了一项,我们下标0表示第一项,接下来就是递推公式我们都知道斐波那契数列的规律就是从第三项开始后面的项等于前两项的和,接下来是初始化,这个很简单,就是前两项初始化为1就可以了,最后我们确定遍历顺序我们肯定是从前往后遍历,因为我们需要由前面的值才能推导出后面的值,那接下来我们就看一下代码:

class Solution {
public:int fib(int n) {if (n <= 1) return n;vector<int> dp(n + 1);dp[0] = 1;dp[1] = 1;for (int i = 2; i <= n; ++i){dp[i] = dp[i - 1] + dp[i - 2];}return dp[n - 1];}
};

        代码我就不解释了相信大家都可以看明白,这是动态规划的最基本的入门题目,我们就进入下一道题目。

第二题对应力扣编号为70的题目爬楼梯

       我们进入今天的第二题,我们看一下题目描述:

        想必大家对爬楼梯问题应该也是相当熟悉了,我们就直接按照动规五部曲来解决,首先是确定dp数组的含义,很明显我们的数组含义就是方法数,递推公式也是很简单的,就是两种方法的和,一个是走一步上来的,一个是走两步上来的,我们两种情况相加就可以,初始化这个需要注意一下,我们应该一层楼初始化为1,两层楼初始化为2,接下来我们就遍历即可,遍历顺序应该也是从前往后,因为还是前面的推导后面的,那我们就直接看一下代码:

class Solution {
public:int climbStairs(int n) {if (n <= 1) return 1;vector<int> dp(n + 1);//如果不初始化会默认dp[0] = 0但有了前面一句就不会了dp[1] = 1;dp[2] = 2;for (int i = 3; i <= n; ++i){dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];}
};

第三题对应力扣编号为746的题目使用最小花费爬楼梯

       这是我们今天的最后一道题目,这道题目的确很有动态规划的感觉了,其实前面两道还是很入门的,这一道开始大家就要开始小心了,我们来看一下题目要求:

      按照动规五部曲,我们首先要确定dp数组的含义,dp[i]表示到第i层楼的最少花费,随后大家在这道题目里楼梯顶部是什么意思,是要比我们cost数组多出一层的,我们cost数组只到了最高层还没到顶层,这个大家要注意,所以大家应该了解了我们最后的返回值应该是dp[cost.size()],随后就是遍历顺序很明显从前往后,还是台阶要从前面爬到后面,从底层爬到顶层才可以,接下来就是初始化的问题,这个得注意,题目说我们可以选择下标为0或者是下标为1的台阶开始所以dp[0]与dp[1]都初始化0都可以不用花费,接下来就是我们的转移方程,就是我当前的楼梯应该是前一个台阶或者是后一个台阶上来的,同时要加上花费,这样我们就可以写出代码:

class Solution {
public:int minCostClimbingStairs(vector<int>& cost) {vector<int> dp(cost.size() + 1);dp[0] = 0;dp[1] = 0;for (int i = 2; i <= cost.size(); ++i){dp[i] = min(dp[i - 1] + cost[i - 1],dp[i - 2] + cost[i - 2]);}return dp[cost.size()];}
};

       代码我就不解释了,大家一定都可以看明白,还是状态转移的时候一定要弄清楚我们的dp数组表示的是什么,这样大家就不会不明白为什么还要加上cost的情况。其实大家只要不明白动态规划类的题目大家就需要去思考我们的dp数组表示的是什么含义。

今日总结

        今天是动态规划的第一天,其实还是轻松的,以前就由基础,复习一遍就可以了,大家在以后的题目中都要按照动规五部曲的思路去解题,遇到不明白的就去思考这五步哪一步没有走好,我们明天再见!

相关文章:

  • 【​​HTTPS基础概念与原理​】对称加密与非对称加密在HTTPS中的协作
  • 掌握Docker:从运行到挂载的全面指南
  • Openshift节点Disk pressure
  • mybatis plus (sqlserver) 根据条件来获取id最大的,或者是新增的最新的一条记录(同条件可能会有多条出现)
  • Java—— 可变参数、集合工具类、集合嵌套、不可变集合
  • [数据结构]6. 队列-Queue
  • C++学习细节回顾(汇总二)
  • 【交互 / 差分约束】
  • AD 规则的使能及优先级的设置
  • 机密虚拟机的威胁模型
  • Java 与 Go 语言对比
  • 【 Java开发枚举值规范】
  • NACOS基于长链接的⼀致性模型
  • 从Transformer到多模态智能,剖析人工智能时代的核心引擎​​
  • 在Linux中如何使用Kill(),向进程发送发送信号
  • 编程题 03-树2 List Leaves【PAT】
  • 为什么要选择七彩喜数字康养平台?加盟后有何优势?
  • Oracle版本、补丁及升级(12)——补丁及补丁集
  • 2011-2020年各省粗离婚率数据
  • 解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs- consistency is the key
  • 上海“城市文明开放麦”全城总动员,樊振东担任首位上海城市文明大使
  • 向猫学习禅修之后,你会发现将生活降格为劳作是多么愚蠢
  • 国新办将就2025年4月份国民经济运行情况举行新闻发布会
  • KPL“王朝”诞生背后:AG和联赛一起迈向成熟
  • 广东早熟荔枝“抢滩”上海,向长三角消费者喊话:包甜,管够
  • 国家林草局原党组成员、副局长李春良接受审查调查