【算法】一文带你快速入门动态规划算法以及动规中的空间优化

在这里插入图片描述

君兮_的个人主页

即使走的再远,也勿忘启程时的初心

C/C++ 游戏开发

Hello,米娜桑们,这里是君兮_,如果给算法的难度和复杂度排一个排名,那么动态规划算法一定名列前茅。在最开始没有什么整体的方法的时候,我也曾经被动态规划折磨过很长时间,通过我一段时间的刷题和不断的学习,逐渐有了一套自己有关动态规划算法的心得和经验,今天就通过一些比较简单的题目带大家快速上手动态规划算法

  • 好了废话不多说,开始我们今天的学习吧!!

    动态规划算法

    • 一 什么是动态规划算法
      • 动态规划算法的大致公式
      • 1 求第 N 个泰波那契数
        • 算法原理解析
        • 编写代码
      • 2 解码方法
        • 算法原理解析
        • 编写代码
    • 二 空间优化(背包问题)
    • 总结

一 什么是动态规划算法

  • 动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。
  • 动态规划算法的基本思想是:将原问题分解为若干个子问题,逐个求解子问题,记录每个子问题的解,避免重复计算,最终得到原问题的解。动态规划算法通常用于具有重叠子问题和最优子结构性质的问题,
  • 好了,相信上面这段话没有基础你应该是看不懂的,我们直接说人话
  • 动态规划算法适用于把一个复杂的问题分解成多个子问题,通过解决子问题的方式得到有关原问题的有效信息,最终通过不断的递推得到原问题的解
  • 核心思想就是分治或者说递推,从题目中给的有效信息中最终推出我们想要的结果

动态规划算法的大致公式

不必严格照着这个公式走,前面的步骤是一样,后面的步骤具体问题具体分析即可

  • 1.状态表示
    分析题目,根据题目的要求找出相同的子问题。找出dp表(一般是一维数组或者二维数组)里面的值的含义是什么?(一般都是我们要求的量)

  • 2.状态转移方程
    分析子问题之间的联系(及dp表里各位置中的值的联系),推出一个类似于递推公式的状态转移方程。

  • [x]3.初始化
    为了保证我们在填dp表时不出现越界访问这种情况,我们需要对边界值进行判断以及通过有效信息来对dp表中的边界值进行初始化

  • 4.填表顺序
    在进行上述的几步操作后,我们需要把我们的dp表填满来解决实际问题了,此时是从大到小填还是从小到大填,我们要根据上述操作得到的有效信息结合题目实际具体判断

  • 5.返回值
    把dp表填满后,我们要结合题目要求确定返回值来解题了

  • 我知道,在这里干讲方法没人能听的懂,下面就通过上述这个解题方法带大家来解决几个实际问题。


1 求第 N 个泰波那契数

  • 原题leetcode链接在这里 第 N 个泰波那契数
    在这里插入图片描述
  • 这个可谓是最经典又最简单的动态规划算法题目了,正合适带大家入门,下面我来带大家分析一下题目

算法原理解析

  • 1 状态表示
    给一个整数n 要求我们返回第n个泰波那契数,那么毫无疑问,我们的dp表中的每一个位置表示的就是当n等于这个数时此时的泰波那契数了,也就是 dp[ i ] 表示第i个泰波那契数。
  • 2.状态转移方程
    找出各个dp[i]的值之间的联系,这个题目已经告诉我们了,第i个泰波那契数就是前三个泰波那契数之和,因此我们可以列出下面这个状态转移方程
       dp[i]=dp[i-1]+dp[i-2]+dp[i-3]
  • 3.初始化
    确定dp表的状态转移方程后,我们为了防止越界需要对边界加以判断
    数组的下标是从0开始的 因此当我们对i<3的dp[ i ]进行递推时,就会出现下标越界的情况,因此我们需要对dp[0].dp[1].dp[2]进行初始化,而题目条件也告诉我们了前三个泰波那契数的值(往往我们也可以通过题目给的值来倒推哪些地方需要注意越界提前初始化)
  • 4.填表顺序
    我们知道前三个泰波那契数,而我们需要求第n个泰波那契数,毫无疑问dp表应该从小到大填
  • 5 返回值
    题目要求我们返回第N个泰波那契数,也就是dp[N],这样我们就确定了返回值

有了这上面五步的分析,我们就可以开始进行代码的编写了


编写代码

  • 参考代码如下
class Solution {
public:int tribonacci(int n) {//对可能出现的越界问题进行判断if(n==0)return 0;if(n==1||n==2)return 1;//建立dp表vector<int>dp(n+1);//初始化dp[0]=0;dp[1]=dp[2]=1;for(int i=3;i<=n;i++){//通过状态转移方程,由已知的dp值推出未知的dp[i]=dp[i-1]+dp[i-2]+dp[i-3];}//返回第n个泰波那契数return dp[n];}
};

在这里插入图片描述
ps:不要在意这里的执行用时和消耗内存,实际上这些于leetcode的服务器和你电脑的配置都有一定关系,你的执行用时高不代表你的算法比别人的差哦!

  • 时间复杂度和空间复杂度分析:
    开辟了大小为n+1的vector,循环遍历了dp表一次,时间和空间复杂度均为O(N)。

一个题说明不了什么,我们再来一个稍微有点难度的题帮助大家进一步理解动态规划算法


2 解码方法

原题leetcode链接在这哦 解码方法
在这里插入图片描述
在这里插入图片描述

算法原理解析

一上来很多人可能就蒙了,这怎么拆分成子问题和建立dp表呢?我们一步一步来

  • 1.状态表示
    通过题目的条件,我们选择用以 i 为结尾来分析(以某个位置结尾或者开始是动态规划中非常重要的经验,一定要记住)。其中dp[i]就表示以i为结尾时,此时解码方法的总数
    注意:既然选择了以i为结尾进行状态表示,就不要考虑i+1位置等的值了(以i为开始同理,不要再考虑i-1等位置的值了)
  • 2.状态转移方程
    我们以i为结尾,就可以分为以下两种情况,我通过图片来表示一下
    在这里插入图片描述
    细节由于主要是讲解算法就不多说了,大家自己去考虑一下,其中 a为s[i]的值,b为s[i-1]的值
    根据上述图片,我们是不是就可以得到这样一种状态转移方程
  • dp[ i ]=dp[i-1]+dp[i-2]
  • 3.初始化
    根据状态转移方程,我们可以轻易的看出dp[1]和dp[0]是需要我们手动初始化而不能递归得出的
  • 4.填表顺序
    求一共有几种解码方法自然要从小到大来推和叠加了,因此填表顺序是从小向大
  • 5.返回值
    我们在状态表示时说了,dp[i]表示以i为结尾时,此时解码方法的总数,因此返回值为dp[i]

做好上面这5步后,我们来看看代码怎么编写


编写代码

class Solution {
public:int numDecodings(string s) {//创建dp表//状态转换方程//初始化int n=s.size();//处理边界条件 if(n==1){return s[0]!='0';}vector<int>dp(n);dp[0]=s[0]!='0';if(s[0]!='0'&&s[1]!='0') dp[1]+=1;int t=(s[0]-'0')*10+s[1]-'0';if(t>=10&&t<=26) dp[1]+=1;for(int i=2;i<n;i++){if(s[i]!='0')dp[i]+=dp[i-1];t=(s[i-1]-'0')*10+s[i]-'0';if(t>=10&&t<=26) dp[i]+=dp[i-2];}return dp[n-1];// //优化边界和初始化//多开一个空间 把之前dp[1]的判断直接放入循环中,增加代码复用率// vector<int> dp(n+1);// dp[0]=1;// dp[1]=s[1-1]!='0';// for(int i=2;i<=n;i++)// {//     if(s[i-1]!='0')//     dp[i]+=dp[i-1];//     int t=(s[i-2]-'0')*10+s[i-1]-'0';//     if(t>=10&&t<=26) dp[i]+=dp[i-2];// }// return dp[n];}
};

在这里插入图片描述

  • ps:这里的注释里也是一种完整的方法以及对我们算法的一些繁琐的地方的优化,由于本文主要偏入门动态规划算法,感兴趣大家就自己看看吧,有不懂的地方可以评论区提出或者私信我。

  • 时间复杂度和空间复杂度分析:
    很容易可得出,时间和空间复杂度均为O(N)。


二 空间优化(背包问题)

  • 在动态规划问题中还有一种常用的空间优化思想,这里也一起给大家介绍一下吧

  • 为了方便讲解,这里我们以第 N 个泰波那契数这个题目为例给大家讲解空间优化

  • 在对该题进行解答时,我们开辟了n+1个空间

vector<int>dp(n+1);
  • 我们仔细回顾一下这个题目,会发现,在得到第 N 个泰波那契数时,我们每个数都只用一次就朝前递推了,可是我们还是开辟了n+1大小的空间来保存它,实际上我们只需要四个数 Tn,Tn-1,Tn-2,Tn-3,那么开辟这么大的空间是不是就有点浪费了?
  • 因此,我们在这里使用滚动数组的方法来对空间进行一下优化
class Solution {
public:int tribonacci(int n) {//含背包机制的空间优化的动态规划算法int a=0;int b=1,c=1;int d=0;if(n==0)return 0;if(n==1||n==2)return 1;for(int i=3;i<=n;i++){d=a+b+c;a=b;b=c;c=d;}return d;}};

在这里插入图片描述

  • 四个变量来进行动态规划一样能过,其他类似的问题也可以采用类似的思想来节省空间

总结

  • 好啦,我们今天的内容就先到这里啦!虽然这两个有关动态规划的问题都不算太难,但是把动态规划的基本思想都包含在内了,其次,一下讲那种很难的题大家也不容易理解。弄懂了简单的题目打好基础才更有利于我们之后的学习,因此如果你想弄懂这块的话,这两道题还是建议你认真去做做哦!!
  • 有任何的问题和对文章内容的疑惑欢迎在评论区中提出,当然也可以私信我,我会在第一时间回复的!!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 图书管理系统

1.需求分析 1.1项目需求分析简介 1.1.1信息需求分析 (1) 图书信息&#xff1a;包括书籍编号&#xff0c;书籍名称&#xff0c;出版社&#xff0c;作者&#xff0c;库存量&#xff0c;出版日期&#xff0c;价格&#xff0c;库存&#xff0c;剩余量&#xff0c;类别等&#xf…

上下固定中间自适应布局

实现上下固定中间自适应布局 1.通过position&#xff1a;absolute实现 定义如下结构 <body> <div class"container"> <div class"top"></div> <div class"center"></div> <div class"bottom&…

清平乐-春风丽日

今天&#xff0c;是2024年农历除夕日&#xff0c;远方家人已于昨夜风尘扑扑地倦鸟归巢&#xff0c;团聚过龙年&#xff0c;今晨酣睡未起。老龄笔者心情极佳&#xff0c;一夜好梦醒来&#xff0c;推窗仰头展望苍穹&#xff0c;喜上心头&#xff1a;啊&#xff01;接连几天的小雨…

小区创业项目推荐:小投资大回报的店铺类型

作为一位拥有5年鲜奶吧创业经验的自媒体博主&#xff0c;我深知在小区内寻找一个既小投资又能带来大回报的创业项目是多么重要。今天&#xff0c;我要为大家推荐的&#xff0c;正是这样一个项目——鲜奶吧。 一、鲜奶吧&#xff1a;小区内的健康食品新宠 随着健康饮食观念的深…

STL之list容器的介绍与模拟实现+适配器

STL之list容器的介绍与模拟实现适配器 1. list的介绍2. list容器的使用2.1 list的定义2.2 list iterator的使用2.3 list capacity2.4 list element access2.5 list modifiers2.6 list的迭代器失效 3. list的模拟实现3.1 架构搭建3.2 迭代器3.2.1 正向迭代器3.2.2反向迭代器适配…

【doghead】uv_loop_t的创建及线程执行

worker测试程序,类似mediasoup对uv的使用,是one loop per thread 。创建一个UVLoop 就可以创建一个uv_loop_t Transport 创建一个: 试验配置创建一个: UvLoop 封装了libuv的uv_loop_t ,作为共享指针提供 对uv_loop_t 创建并初始化

如何运行心理学知识(心流)来指导工作和生活

如何运用心流来指导工作和生活 如何联系我 作者&#xff1a;鲁伟林 邮箱&#xff1a;thinking_fioa163.com或vlinyes163.com GitHub&#xff1a;https://github.com/thinkingfioa/ReadingSummary 版权声明&#xff1a;文章和记录为个人所有&#xff0c;如果转载或个人学习…

Three.js学习8:基础贴图

一、贴图 贴图&#xff08;Texture Mapping&#xff09;&#xff0c;也翻译为纹理映射&#xff0c;“贴图”这个翻译更直观。 贴图&#xff0c;就是把图片贴在 3D 物体材质的表面&#xff0c;让它具有一定的纹理&#xff0c;来为 3D 物体添加细节的一种方法。这使我们能够添加…

机器人搬砖 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 机器人搬砖&#xff0c;一共有N堆砖存放在N个不同的仓库中&#xff0c;第 i 堆中有 bricks[i] 块砖头&#xff0c;要求在8小时内搬完。 机器人每小时能搬砖的数量…

鸿蒙开发-UI-图形-图片

鸿蒙开发-UI-组件 鸿蒙开发-UI-组件2 鸿蒙开发-UI-组件3 鸿蒙开发-UI-气泡/菜单 鸿蒙开发-UI-页面路由 鸿蒙开发-UI-组件导航-Navigation 鸿蒙开发-UI-组件导航-Tabs 文章目录 一、基本概念 二、图片资源加载 1. 存档图类型数据源 2.多媒体像素图 三、显示矢量图 四、图片…

【python】if __name__ == ‘__main__‘:

if __name__ __main__: 是一个Python脚本中使用的常见结构&#xff0c;用来判断该脚本文件是直接运行的还是被导入到其他文件中运行的。 当一个Python文件被运行时&#xff0c;Python解释器会自动创建一些特殊的变量&#xff0c;__name__就是其中之一。如果这个文件是作为主程…

获取视频帧图片

在实现了minio文件上传的基础上进行操作 一、编写pom <dependency><groupId>org.jcodec</groupId><artifactId>jcodec</artifactId><version>0.2.5</version> </dependency> <dependency><groupId>org.jcodec<…