当前位置: 首页 > 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数组表示的是什么含义。

今日总结

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

http://www.xdnf.cn/news/451189.html

相关文章:

  • W1电力线载波通信技术
  • Linux 常用命令 -hostnamectl【主机名控制】
  • Mixup
  • 【RabbitMQ】发布确认机制的具体实现
  • 3Dblox
  • 【Python3教程】Python3基础篇之输入与输出
  • 车载网关--- 职责边界划分与功能解耦设计
  • 安卓基础(Bitmap)
  • 致远OA项目管理应用包简介【附百度网盘链接】
  • scratch基础-外观模块
  • 基于EFISH-SCB-RK3576/SAIL-RK3576的智能安检机技术方案‌
  • 基于SpringBoot+Vue的房屋租赁管理系统源码包(完整版)开发实战
  • matlab提取脑电数据的五种频域特征指标数值
  • 电脑软件出现应用程序未响应
  • JJJ:linux ida
  • 深入掌握 Python 切片操作:解锁数据处理的高效密码
  • hadoop知识点
  • Guix System 系统详解:从架构到生态的深度解析
  • WebGL图形编程实战【7】:变换流水线 × 坐标系与矩阵精讲
  • 【ESP32-S3】Guru Meditation Error 崩溃分析实战:使用 addr2line 工具 + bat 脚本自动解析 Backtrace
  • Blender 入门教程(二):纹理绘制
  • Java NIO 深度解析:突破传统IO的性能瓶颈
  • 【Linux】基础指令(Ⅱ)
  • Joker 智能可视化开发平台 AI胜出的关键
  • 解锁健康生活:现代养生实用方案
  • 【c语言】自定义类型:结构体
  • vue和springboot交互数据,使用axios【跨域问题】
  • 【springcloud学习(dalston.sr1)】使用Feign实现接口调用(八)
  • python打卡day25@浙大疏锦行
  • OpenCV + PyAutoGUI + Tkinter + FastAPI + Requests 实现的远程控制软件设计方案