代码随想录算法训练营DAY38|C++动态规划Part.1|动态规划理论基础、509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯

文章目录

  • 动态规划理论基础
    • 什么是动态规划
    • 动态规划的解题步骤
      • DP数组以及下标的含义
      • 递推公式
      • DP数组初始化
      • DP数组遍历顺序
      • 打印DP数组
      • 动态规划五部曲
    • 动态规划应该如何debug
  • 509.斐波那契数
    • 什么是斐波那契数列
    • 动态规划五部曲
      • 确定dp数组下标以及含义
      • 确定递推公式
      • dp数组如何初始化
      • 确定遍历顺序
      • 打印DP数组
    • 代码实现
    • CPP代码
  • 70.爬楼梯
    • 题意分析
    • 动规五部曲
      • 确定dp数组下标以及含义
      • 确定递推公式
      • dp数组如何初始化
      • 确定遍历顺序
      • 打印DP数组
    • 扩展题
    • CPP代码
  • 746.使用最小花费爬楼梯

在这里插入图片描述

动态规划理论基础

什么是动态规划

动态规划(Dynamic Programming, DP),如果某一个问题有很多重叠子问题,这样往往是用动态规划是最有效的。

所以动态规划中每一个状态一定是由上一个状态推导出来的这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。

对于刷题来说就抓住一句话:

动规是由前一个状态推导出来的,而贪心是从局部直接选出最优的

动态规划的解题步骤

在全面总结动态规划解题步骤前,同时也是做动态规划类题目之前,我们要先搞明白以下几个问题:

DP数组以及下标的含义

有很多类问题有一个二维dp数组,其中的行、列的含义一定要搞清楚;同理一维dp数组中的值又是什么呢?在写代码前,一定要搞明白这是什么意思。

递推公式

动态规划递推公式仅仅是一部分,而不是只要掌握了递推公式,动规就变得简单了。

DP数组初始化

dp数组如何初始化其实紧贴着dp数组以及下标含义,如果dp数组里是什么,各个维度含义是什么,那dp数组的初始化更加无从谈起了。

DP数组遍历顺序

对于背包类问题,遍历顺序是非常有讲究的,所以每道题一定要弄清他们的遍历顺序。

打印DP数组

如果题目通过不了,首先应该考虑是不是dp数组出了问题,我们应该吧dp数组打印出来看是否符合预期

动态规划五部曲

一定要仔细分析上述的五大问题

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

动态规划应该如何debug

做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果

然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。

这样才是一个完整的思考过程,而不是一旦代码出问题,就毫无头绪的东改改西改改,最后过不了,或者说是稀里糊涂的过了

这里给出卡哥写的自我debug的灵魂三问:

  • 这道题目我举例推导状态转移公式了么?
  • 我打印dp数组的日志了么?
  • 打印出来了dp数组和我想的一样么?

509.斐波那契数

力扣题目链

文章链接:509.斐波那契数列

视频链接:手把手带你入门动态规划 | leetcode:509.斐波那契数

状态:迭代法还是会写一写

什么是斐波那契数列

动态规划五部曲

确定dp数组下标以及含义

dp[i]表示第i个斐波那契数值为dp[i]

确定递推公式

斐波那契数的递推公式很明显: d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i] = dp[i - 1] + dp[i - 2] dp[i]=dp[i1]+dp[i2]

dp数组如何初始化

斐波那契的初始化也很简单 [ 0 , 1 , 1 , 2 , 3 , 5 , 8 ] [0, 1, 1, 2, 3, 5, 8] [0,1,1,2,3,5,8]

由数学归纳可知: d p [ 0 ] = 0 ; d p [ 1 ] = 1 ; dp[0] = 0; dp[1] = 1; dp[0]=0;dp[1]=1;

在很多题目中,dp数组的初始化往往也依赖于递推公式

确定遍历顺序

本题中,遍历顺序从前向后即可。(有一些题目从后向前遍历;有一些题目两层for循环,其先先后顺序也有说法)

打印DP数组

这个主要是用来debug的

代码实现

vector<int> dp(n+1);
//初始化
dp[0] = 0; dp[1] = 1;
for (i = 2; i <= n; i++)dp[i] = dp[i-1] + dp[i-2];
return dp[n];

对状态进行压缩,只需要维护两个数值就可以了,不需要记录整个序列.代码可以缩减为

int fib(int N){if (N <= 1) return N;int dp[2];dp[0] = 0;dp[1] = 1;for (int i = 2; i <= N; i++){int sum = dp[0] + dp[1];dp[0] = dp[1];dp[1] = sum;}return dp[1];
}

时间复杂度为O(2^n)的递归解法:

int fib(int N){if (N < 2) return N;return fib(N - 1) + fib(N - 2);
}

CPP代码

class Solution {
public:int fib(int N) {if (N <= 1) return N;vector<int> dp(N + 1);dp[0] = 0;dp[1] = 1;for (int i = 2; i <= N; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[N];}
};
//只维护两个数值
class Solution {
public:int fib(int N) {if (N <= 1) return N;int dp[2];dp[0] = 0;dp[1] = 1;for (int i = 2; i <= N; i++) {int sum = dp[0] + dp[1];dp[0] = dp[1];dp[1] = sum;}return dp[1];}
};
//递归
class Solution {
public:int fib(int N) {if (N < 2) return N;return fib(N - 1) + fib(N - 2);}
};

70.爬楼梯

力扣题目链接

文章讲解:70.爬楼梯

视频讲解:带你学透动态规划-爬楼梯|LeetCode:70.爬楼梯)

状态:

题意分析

如果对于一个n阶台阶,每次你可以爬 12 个台阶。有多少种不同的方法可以爬到楼顶。

如果台阶一共只有1阶,一共只有1

如果台阶有2阶,一共有2

如果台阶有3阶,一共有3

如果台阶有4阶,一共有5

本质上,当前台阶有几种方法,主要依赖于前两个状态

其实这就是递推关系。这种递推关系可以用动态规划来解决。

动规五部曲

确定dp数组下标以及含义

dp[i],达到i阶有dp[i]种方法。

确定递推公式

dp[i - 2]表示达到i-2阶有dp[i - 2]种方法

dp[i - 1]表示达到i-1阶有dp[i - 1]种方法

dp[i]表示达到i阶有dp[i]种方法

d p [ i ] = d p [ i − 2 ] + d p [ i − 1 ] dp[i] = dp[i-2]+dp[i-1] dp[i]=dp[i2]+dp[i1]

dp数组如何初始化

从递推公式可以看出,最重要的就是初始化数组的前几位

dp[0] = 1还是dp[0] = 0

因为我们dp[2] = 2,从递推公式出发,dp[0]应该初始化成1。同时题目中也说过,n为正整数

在代码随想录的代码中,是不初始化0的,而是直接初始化dp[2]dp[1]

确定遍历顺序

从前向后遍历即可

打印DP数组

用于debug

其实本质上,从上文论述的规律可以看出,其实本题就是一个斐波那契数列

扩展题

一步可以走m个台阶,爬n阶的楼梯有多少种方法。

词题可以用完全背包的思路来解决。

CPP代码

//还是只维护两个数组
class Solution {
public:int climbStairs(int n) {if (n <= 3) return n;int dp[2];dp[0] = 1; dp[1] = 2;for (int i = 3; i <= n; ++i) {int cur = dp[0] + dp[1];dp[0] = dp[1];dp[1] = cur;}return dp[1];}
};

746.使用最小花费爬楼梯

力扣题目链接

文章讲解:746.使用最小花费爬楼梯

视频讲解:动态规划开更了!| LeetCode:746. 使用最小花费爬楼梯

状态:相较于前两个题目,难度一下就上来了,我个人感觉是贪心和动态规划的结合。

在题目描述中,我们可以选择从下标为0或下标为1的台阶开始爬楼梯。

思路

dp数组含义

想给出结论,本题仍然只需要一个一维的dp数组,其下标记录我们到达了哪个台阶,其中的值就是体力的最小消耗。

以上的推导都是怎么来的呢?

要求的是爬到楼顶,那么我们dp数组应该得用下标来表示我们爬的位置,看是不是到楼顶了;

然后我们要求一个最小消耗,那么我们的dp数组刚好可以存到达该层的一个消耗,刚好逻辑就闭环。

综上:

dp[i]表示到达i位置所需要的花费为dp[i]

递推公式

本题中我们要求的就是dp[i],那么如何跳到dp[i]呢?我们可以从dp[i-1]跳一步到dp[i],也可以从dp[i-2]跳两步到dp[i]

如果从dp[i-1]跳到dp[i]的话,所需要的花费是dp[i-1] + cost[i-1]

如果从dp[i-2]跳到dp[i]的话,所需要的花费是dp[i-2] + cost[i-2]

dp[i]表示到达i位置所需要的花费为dp[i]

显然递推公式为: d p [ i ] = m i n ( d p [ i − 1 ] + c o n s t [ i − 1 ] , d p [ i − 2 ] + c o n s t [ i − 2 ] ) dp[i] = min(dp[i-1] + const[i-1], dp[i-2] + const[i-2]) dp[i]=min(dp[i1]+const[i1],dp[i2]+const[i2])

初始化

很明显,本题只要初始化了dp[1]dp[0]就可以把递推公式打通了。

//题意表明了,可以选择从0层或者从第1层开始跳
dp[0] = 0;	//到达0位置最小花费为0
dp[1] = 0;	//到底1位置最小花费也是0. 因为我们可以选择嘛

遍历顺序

从零往后去遍历

因为是模拟台阶,而且dp[i]由dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。

打印dp数组

打印出来看是不是和我们预想的一样

CPP代码

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()];}
};//只维护两个数字
class Solution {
public:int minCostClimbingStairs(vector<int>& cost) {int dp0 = 0;int dp1 = 0;for (int i = 2; i <= cost.size(); i++) {int dpi = min(dp1 + cost[i - 1], dp0 + cost[i - 2]);dp0 = dp1; // 记录一下前两位dp1 = dpi;}return dp1;}
};

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

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

相关文章

数据分析:甲基化分析-从DNA methylation的IDAT文件到CpG site的Beta values

介绍 DNA Methylation和疾病的发生发展存在密切相关&#xff0c;它一般通过CH3替换碱基5‘碳的H原子&#xff0c;进而调控基因的转录。常用的DNA methylation是Illumina Infinium methylation arrays&#xff0c;该芯片有450K和850K&#xff08;也即是EPIC&#xff09;。 该脚…

Mac虚拟机装Windows Mac环境安装Win虚拟机教程 macbookpro安装windows虚拟机

在如今多元的数字时代&#xff0c;我们经常需要在不同的操作系统环境下进行工作和学习。而对于Mac用户来说&#xff0c;有时候需要在自己的电脑上安装Windows操作系统&#xff0c;以体验更多软件及功能&#xff0c;而在Mac安装Windows虚拟机是常用的一种操作。下面就来看看Mac虚…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release&#xff0c;发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

数字身份管理:Facebook如何利用区块链技术?

随着数字化进程的加速&#xff0c;个人身份管理已成为一个关键议题。在这方面&#xff0c;区块链技术正在逐渐展现其巨大潜力。作为全球最大的社交媒体平台&#xff0c;Facebook也在积极探索和应用区块链技术来改进其数字身份管理系统。本文将深入探讨Facebook如何利用区块链技…

VSCODE通过SFTP链接VM进行开发

在vscode插件里面搜索sftp&#xff0c;安装。 安装之后&#xff0c;按ctrlshiftp&#xff0c;找到sftp的config 然后填写刚刚的IP&#xff0c;然后是你的用户名密码 如果是通过密钥链接的话就是这样配置 然后切换到这个sftp的tab里面 然后在你的项目右键&#xff0c;然后选择op…

el-date-picker 禁用时分秒选择(包括禁用下拉框展示)

2024.04.26今天我学习了对el-date-picker进行禁用时分秒&#xff0c; 在使用el-date-picker组件的时候&#xff0c;我们有可能遇到需要把时分秒的时间固定&#xff0c;然后并且不能让他修改&#xff1a; 1714120999296 比如右上角的这个时间&#xff0c;我们要给它固定是‘08:…

CSP初赛知识精讲--线性数据结构

第十五节 线性树形结构 基础知识 线性表 线性表是指由n个具有相同特性的数据元素组成的有限序列&#xff0c;是最基本、最简单&#xff0c;也是最常用的一种数据结构。队列、栈、链表、哈希表等数据结构逻辑上都属于线性表。一般来讲&#xff0c;表中数据之间的关系是一对一的…

WPS Word自动编号转文本

原理 使用WPS自带的宏功能&#xff0c;一键替换 过程 调出"开发工具"选项 文件->选项->自定义功能区->选中开发工具->确认 创建宏 工具 -> 运行宏 编写宏 在弹出来的框里&#xff0c;粘贴代码 如果弹窗类似如下&#xff0c;这是JS宏 则…

Spark-机器学习(5)分类学习之朴素贝叶斯算法

在之前的文章中&#xff0c;我们学习了回归中的逻辑回归&#xff0c;并带来简单案例&#xff0c;学习用法&#xff0c;并带来了简单案例。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵…

阿里云企业邮箱API的使用方法?调用限制?

阿里云企业邮箱API性能如何优化&#xff1f;配置邮箱API的优势&#xff1f; 阿里云企业邮箱以其稳定、高效和安全的特点&#xff0c;受到了众多企业的青睐。而阿里云企业邮箱API的开放&#xff0c;更是为企业提供了更加灵活、便捷的管理和操作方式。下面&#xff0c;我AokSend…

用过最佳的wordpress模板

西瓜红&#xff0c;作为一种充满活力和激情的颜色&#xff0c;总是能给人留下深刻的印象。当这种鲜艳的色彩与经典的设计元素相结合时&#xff0c;就能打造出一款既时尚又实用的WordPress企业模板。今天&#xff0c;我们向您隆重推荐这款西瓜红经典配色WordPress企业模板。 这…

User Agent 解析:它是什么以及工作原理

什么是User Agent? UserAgent&#xff0c;简称UA&#xff0c;是一个使服务器能够识别用户使用的浏览器类型、版本以及运行浏览器的操作系统等信息的字符串。它作为浏览器请求头部信息的一部分发送给服务器&#xff0c;以便服务器可以返回合适格式和版本的内容。 跟Cookie一样…

proteus+stm32+CubeMX+dht11+lcd1602

浅浅记录下过程遇到的问题&#x1f921;&#x1f921;&#x1f921; 1 供电网配置错误&#xff08;加上就好了 新起个名也会出这个 / 电源不起名 不创建估计项目也会&#xff09;没zet6的 proteus 里 固件库 账号注册半天没成 就用的stm32F103R6的然后发现单片机不输出高低电平…

阿里云服务器开放端口的最最最正确的方法

今天&#xff0c;我突然发现阿里云服务器端口无法访问ElasticSearch了&#xff0c;嗯&#xff1f;&#xff1f;&#xff1f;肿么回事&#xff0c;搜遍了全网&#xff0c;终于在我身心俱疲后找到了原因&#xff1a; 现在我来总结一下出现这种问题的原因以及解决步骤 &#xff1a…

电机入门1

文章目录 122.12.22.3 33.13.23.33.4 1 2 2.1 电机板 驱动板电机分类 驱动器分类 转速 转向扭矩定时器 ADC 2.2 PID 自动控制 的核心闭环控制算是 PID的应用 2.3 无刷电机用的 可大大提高其控制效率 和控制精度 3 开发板的IO 电流太小了 20~25ma 电机要A 驱动板 信号放大没舵…

守护人类健康:人工智能赋能医疗领域创新应用

常言道&#xff0c;“如果说人生是一场漫长的马拉松&#xff0c;那么健康将是决定跑道长度的关键因素。”健康是幸福生活和社会发展的基石。随着智能化时代的到来&#xff0c;人工智能技术在医疗健康领域的应用也日益广泛&#xff0c;成为了维护和促进人类健康的新工具。无论是…

《汇编语言》- 读书笔记 - 综合研究

《汇编语言》- 读书笔记 - 综合研究 研究试验 1 搭建一个精简的 C 语言开发环境1. 下载2. 配置3. 编译4. 连接 研究试验 2 使用寄存器1. 编一个程序 ur1.c &#xff08; tcc 用法&#xff09;tcc 编译连接多个源文件tlink 手动连接 2.用 Debug 加载 ur1.exe&#xff0c;用u命令…

如何在现场电脑是部署onnx模型

调整版本为Release x64&#xff08;关键&#xff09;并配置好CUDA和CUDNN。 注意&#xff1a;Release | x64是基类主配置&#xff0c;包含目录下有编译器的一些链接库 以及一些库目录&#xff1a; 以及附加依赖项&#xff1a; msvcprt.lib kernel32.lib user32.lib gdi32.l…

代码随想录算法训练营day40

题目&#xff1a;343. 整数拆分、96.不同的二叉搜索树 参考链接&#xff1a;代码随想录 343. 整数拆分 思路&#xff1a;五部曲来走。dp数组&#xff0c;dp[i]用于记录拆i得到的最大乘积和&#xff0c;我们要求的也就是dp[n]&#xff1b;递推公式&#xff0c;我们想拆分i&am…

ZooKeeper集群的搭建

ZooKeeper集群的搭建 将master节点的/data目录下的ZooKeeper安装包解压到/opt/software目录下 tar -zxvf apache-zookeeper-3.6.3-bin.tar.gz -C /opt/software/在master节点切换至ZooKeeper安装目录的conf目录下&#xff0c;将zoo_sample.cfg重命名为zoo.cfg&#xff0c;并…