【算法专题】动态规划之斐波那契数列模型

动态规划1.0

  • 动态规划 - - - 斐波那契数列模型
    • 1. 第 N 个泰波那契数
    • 2. 三步问题
    • 3. 使用最小花费爬楼梯
    • 4. 解码方法

动态规划 - - - 斐波那契数列模型

1. 第 N 个泰波那契数

题目链接 -> Leetcode -1137. 第 N 个泰波那契数

Leetcode -1137. 第 N 个泰波那契数

题目:泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn + 3 = Tn + Tn + 1 + Tn + 2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

示例 1:
输入:n = 4
输出:4
解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4

示例 2:
输入:n = 25
输出:1389537

提示:
0 <= n <= 37
答案保证是一个 32 位整数,即 answer <= 2 ^ 31 - 1。

思路:

  1. 状态表示:这道题可以「根据题目的要求」直接定义出状态表示:dp[i] 表示:第 i 个泰波那契数的值。
  2. 状态转移方程:dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
  3. 初始化:从我们的递推公式可以看出, dp[i] 在 i = 0 以及 i = 1 的时候是没有办法进行推导的,因为 dp[-2] 或 dp[-1] 不是一个有效的数据。因此我们需要在填表之前,将 0, 1, 2 位置的值初始化。题目中已经告诉我们 dp[0] = 0, dp[1] = dp[2] = 1 。
  4. 填表顺序:从左往右
  5. 返回值:应该返回 dp[n] 的值。

代码如下:

		class Solution {public:int tribonacci(int n){if (n == 0 || n == 1) return n;// 动态规划,当前位置的值等于前三个位置的值相加vector<int> dp(n + 1);dp[1] = dp[2] = 1; // 先初始化前面的位置// 开始使用动态规划for (int i = 3; i <= n; i++)dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];return dp[n];}};

2. 三步问题

题目链接 -> Leetcode -面试题 08.01.三步问题

Leetcode -面试题 08.01.三步问题

题目:三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。
实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

示例1 :
输入:n = 3
输出:4
说明 : 有四种走法

示例2 :
输入:n = 5
输出:13

提示 :

  • n范围在[1, 1000000]之间

思路:

  1. 状态表示:dp[i] 表示:到达 i 位置时,一共有多少种方法。

  2. 状态转移方程:
    以 i 位置状态的最近的⼀步,来分情况讨论:
    如果 dp[i] 表示小孩上第 i 阶楼梯的所有方式,那么它应该等于所有上一步的方式之和:
    i. 上一步上一级台阶, dp[i] += dp[i - 1] ;
    ii. 上一步上两级台阶, dp[i] += dp[i - 2] ;
    iii. 上一步上三级台阶, dp[i] += dp[i - 3] ;
    综上所述, dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]

  3. 初始化从我们的递推公式可以看出, dp[i] 在 i = 0, i = 1 以及 i = 2 的时候是没有办法进行推导的,因为 dp[-3] dp[-2] 或 dp[-1] 不是⼀个有效的数据。因此我们需要在填表之前,将 1, 2, 3 位置的值初始化。根据题意, dp[1] = 1, dp[2] = 2, dp[3] = 4 。

  4. 填表顺序:从左往右

  5. 返回值:应该返回 dp[n] 的值。

代码如下:

		class Solution {public:int waysToStep(int n){if (n == 1 || n == 2) return n;vector<int> dp(n + 1);dp[1] = 1, dp[2] = 2, dp[3] = 4; // 初始化// 走到当前台阶的方法数等于,到达前三个台阶的方法数相加;// 因为前三个台阶走一步,走两步,走三步都可以到达当前台阶,加上这一步、两步或三步,都是同一种方法for (int i = 4; i <= n; i++)dp[i] = ((dp[i - 1] + dp[i - 2]) % 1000000007 + dp[i - 3]) % 1000000007;return dp[n];}};

3. 使用最小花费爬楼梯

题目链接 -> Leetcode -746.使用最小花费爬楼梯

Leetcode -746.使用最小花费爬楼梯

题目:给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

示例 1:
输入:cost = [10, 15, 20]
输出:15
解释:你将从下标为 1 的台阶开始。

  • 支付 15 ,向上爬两个台阶,到达楼梯顶部。
    总花费为 15 。

示例 2:
输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出:6
解释:你将从下标为 0 的台阶开始。

  • 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
  • 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
  • 支付 1 ,向上爬一个台阶,到达楼梯顶部。
  • 总花费为 6 。

提示:

  • 2 <= cost.length <= 1000
  • 0 <= cost[i] <= 999

思路:

  1. 状态表示:dp[i] 表示:到达 i 位置时的最小花费。(注意:到达 i 位置的时候,i 位置的钱不需要算上)
  2. 状态转移方程:根据最近的一步,分情况讨论:
  • 先到达 i - 1 的位置,然后支付 cost[i - 1] ,接下来走一步走到 i 位置:dp[i - 1] + csot[i - 1] ;
  • 先到达 i - 2 的位置,然后⽀付 cost[i - 2] ,接下来走一步走到 i 位置:dp[i - 2] + csot[i - 2] 。
  1. 初始化:从我们的递推公式可以看出,我们需要先初始化 i = 0 ,以及 i = 1 位置的值。容易得到 dp[0] = dp[1] = 0 ,因为不需要任何花费,就可以直接站在第 0 层和第 1 层上。
  2. 填表顺序:根据「状态转移方程」可得,遍历的顺序是「从左往右」。
  3. 返回值:根据「状态表示以及题目要求」,需要返回 dp[n] 位置的值。

代码如下:

		class Solution {public:int minCostClimbingStairs(vector<int>& cost){int n = cost.size();// 从第三个阶梯开始,当前阶梯往上爬的费用等于前两个费用的较小值加上爬当前阶梯需要的费用for (int i = 2; i < n; i++)cost[i] = min(cost[i - 1], cost[i - 2]) + cost[i];// 最后返回最后倒数第一个和第二个阶梯的最小值return min(cost[n - 1], cost[n - 2]);}};

4. 解码方法

题目链接 -> Leetcode -91.解码方法

Leetcode -91.解码方法

题目:一条包含字母 A - Z 的消息通过以下映射进行了 编码 :

‘A’ -> “1”
‘B’ -> “2”

‘Z’ -> “26”

要解码已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,“11106” 可以映射为:

“AAJF” ,将消息分组为(1 1 10 6)
“KJF” ,将消息分组为(11 10 6)
注意,消息不能分组为(1 11 06) ,因为 “06” 不能映射为 “F” ,这是由于 “6” 和 “06” 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。
题目数据保证答案肯定是一个 32 位 的整数。

示例 1:
输入:s = “12”
输出:2
解释:它可以解码为 “AB”(1 2)或者 “L”(12)。

示例 2:
输入:s = “226”
输出:3
解释:它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。

示例 3:
输入:s = “06”
输出:0
解释:“06” 无法映射到 “F” ,因为存在前导零(“6” 和 “06” 并不等价)。

提示:

  • 1 <= s.length <= 100
  • s 只包含数字,并且可能包含前导零。

思路:

  1. 状态表示:根据上题的经验,对于大多数线性 dp ,我们经验上都是「以某个位置结束或者开始」做文章,这里我们继续尝试「用 i 位置为结尾」结合「题目要求」来定义状态表示。
    dp[i] 表示:字符串中 [0,i] 区间上,一共有多少种编码方法
  2. 状态转移方程:定义好状态表示,我们就可以分析 i 位置的 dp 值,关于 i 位置的编码状况,我们可以分为下面两种情况:
    i. 让 i 位置上的数单独解码成⼀个字母;
    ii. 让 i 位置上的数与 i - 1 位置上的数结合,解码成一个字母。

    下面我们就上面的两种解码情况,继续分析:
  • 让 i 位置上的数单独解码成一个字母,就存在「解码成功」和「解码失败」两种情况:
    i. 解码成功:当 i 位置上的数在 [1, 9] 之间的时候,说明 i 位置上的数是可以单独解码的,那么此时 [0, i] 区间上的解码方法应该等于 [0, i - 1] 区间上的解码方法。因为 [0, i - 1] 区间上的所有解码结果,后面填上⼀个 i 位置解码后的字母就可以了。此时 dp[i] = dp[i - 1] ;
    ii. 解码失败:当 i 位置上的数是 0 的时候,说明 i 位置上的数是不能单独解码的,那么此时 [0, i] 区间上不存在解码方法。因为 i 位置如果单独参与解码,但是解码失败了,那么前面做的就全部白费了。此时 dp[i] = 0 。
  • 让 i 位置上的数与 i - 1 位置上的数结合在⼀起,解码成一个字母,也存在「解码成功」和「解码失败」两种情况:
    i. 解码成功:当结合的数在 [10, 26] 之间的时候,说明 [i - 1, i] 两个位置是可以解码成功的,那么此时 [0, i] 区间上的解码方法应该等于 [0, i - 2 ] 区间上的解码方法,原因同上。此时 dp[i] = dp[i - 2] ;
    ii. 解码失败:当结合的数在 [0, 9] 和 [27 , 99] 之间的时候,说明两个位置结合后解码失败(这里⼀定要注意 00 01 02 03 04 … 这几种情况),那么此时 [0, i] 区间上的解码方法就不存在了,原因依旧同上。此时 dp[i] = 0 。

综上所述: dp[i] 最终的结果应该是上面四种情况下,解码成功的两种的累加和(因为我们关心的是解码方法,既然解码失败,就不用加入到最终结果中去),因此可以得到状态转移方程( dp[i] 默认初始化为 0 ):

  • 当 s[i] 上的数在 [1, 9] 区间上时: dp[i] += dp[i - 1] ;
  • 当 s[i - 1] 与 s[i] 上的数结合后,在 [10, 26] 之间的时候: dp[i] += dp[i - 2] ;

如果上述两个判断都不成立,说明没有解码方法, dp[i] 就是默认值 0 .

  1. 初始化:可以在最前面加上一个辅助结点,帮助我们初始化。使用这种技巧要注意两个点:
    i. 辅助结点里面的值要保证后续填表是正确的;
    ii. 下标的映射关系

  2. 填表顺序:「从左往右」

  3. 返回值:应该返回 dp[n - 1] 的值,表示在 [0, n - 1] 区间上的编码方法。

代码如下:

		class Solution {public:int numDecodings(string s){int n = s.size();// 创建一个 dp 表,多开一个空间,即添加辅助位置初始化vector<int> dp(n + 1);dp[0] = 1;   // 因为前面的初始化会影响后面的填表,所以此处应该初始化为1// 只要第一个字符不是 0,那么当前位置的解码数就是1if (s[0] != '0') dp[1] = 1;// 开始填表for (int i = 2; i <= n; i++){// 单独自己一个数编码(dp表的下标与原字符串的下标偏移量为1,因为dp表多开了一个空间)if (s[i - 1] >= '1' && s[i - 1] <= '9'){dp[i] += dp[i - 1];}// 和前一个数联合起来编码int tmp = (s[i - 2] - '0') * 10 + (s[i - 1] - '0');if (tmp >= 10 && tmp <= 26){dp[i] += dp[i - 2];}}return dp[n];}};

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

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

相关文章

git如何仅合并项目下的某个文件夹

前言 假设目前在做的一个项目名为demoproject&#xff0c;目前版本为v1.0.0&#xff0c;标准开发都是在demoproject上进行的&#xff0c;但是有一个客户需要做定制化&#xff0c;需要将项目中的一些信息改为客户的&#xff0c;于是基于demoproject拉了一个v1.0.0-custom&#…

Unity C# 异步编程模式之等待直到完成模式(wait-until-done模式)

Unity的协程使用的就是wait-until-done模式&#xff0c;下面放上完整代码&#xff1a; using UnityEngine; using System.Threading; using System;delegate int MyDel(int first, int second);//声明委托类型public class AsyncWaitUntilDoneDemo : MonoBehaviour {void Star…

RabbitMQ解决消息丢失以及重复消费问题

文章目录 1、概念2、基于ACK/NACK机制2.1 基于Spring AMQP框架整合ACK/NACK机制2.2 测试消费失败1.02.3 测试结果1.02.4 测试MQ宕机2.5 测试结果2.0 3、RabbitMQ 如何实现幂等性设计3.1 幂等服务设计思路3.1.1 通过雪花算法生成分布式唯一ID3.1.2 通过枚举类&#xff0c;设计Me…

数据库7种范式

在关系数据库设计中&#xff0c;存在多个范式&#xff0c;通常从第一范式&#xff08;1NF&#xff09;到更高阶的范式。以下是一些常见的数据库范式&#xff1a; 1. 第一范式(1NF) 确保每个表的每个列都包含原子值&#xff0c;不可再分。 每个表都应该有一个主键&#xff1a…

MySQL:ERROR 1067 - Invalid default value for ‘end_time‘【解决办法】

问题描述&#xff08;mysql版本&#xff1a;5.7.36&#xff09;&#xff1a; 今天在使用Navicat可视化工具运行sql文件&#xff0c;发生如下错误&#xff1a; 在图中&#xff0c;sql是没有错误的&#xff0c;但是运行报错Invalid default value for end_time。 解决办法&#…

Python的安装与卸载【Windows系统】

在 Windows 上安装与卸载 Python Python的安装 下载Python 安装Python 下载完后打开安装包 注意最底下的"Add Python 3.8 to Path"&#xff08;将Python加入环境变量&#xff09;一定要勾选&#xff01;&#xff01;&#xff01;这样就可以免去之后环境配置的烦恼…

方差分解(variance decomposition)研究发展史

方差分解(variance decomposition)研究发展史 1 早期技术概述1.1 方差组分分析(variance components analysis, VCA )1.2 方差分析(Analysis of Variance,简称ANOVA)2 交叉嵌套数据结构和早期方差分解技术的局限性3 多层次建模方法的方差分解参考1 早期技术概述 方差分…

计算机网络——应用层(2)

计算机网络——应用层&#xff08;2&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) Web和HTTP概念解读HTTPHTTP请求和响应包含内容常见的请求方法Web缓存优点缺点 总结 DNS提供的服务 小程一言 我的计算机网络专栏&#xff0c;是自己在计算机网络学习过程…

【手搓深度学习算法】用线性回归预测波士顿房价

线性回归 线性回归是一种监督学习方法&#xff0c;用于建立因变量与一个或多个自变量之间的关系。线性回归的目标是找到一条直线&#xff0c;使得所有数据点到这条直线的距离之和最小。 线性回归的基本形式如下&#xff1a; y β 0 β 1 x 1 β 2 x 2 . . . β n x n ϵ…

HTML 基本元素是什么?

"HTML 基本元素" 是指构成 HTML 网页的基本部分。HTML 是超文本标记语言的简称&#xff0c;是一种用于创建网页的标准标记语言。HTML 基本元素包括标题、段落、列表、链接、图片等&#xff0c;这些元素用于构建网页的结构和内容。通过使用 HTML 基本元素&#xff0c;…

Sui 2024 Space首秀精彩集锦

1月5日&#xff0c;Sui Network官方在X平台进行了名为《Looking Ahead: What’s in Store for 2024》的2024 Space首秀&#xff0c;Mysten Labs联合创始人兼首席产品官Adeniyi Abiodun和首席技术官Sam Blackshear&#xff0c;与全球Sui支持者一起探讨Sui网络的2024发展大计&…

Kubernetes 专栏目录

知识点 1. nodeselector 知识点 2. daemonset 通过 label 设置指定节点启动 pod 3. webhook 失败策略 资源 yaml 模板 1. pod yaml 字段含义 2. service yaml 字段含义 kubectl 1. kubectl 给资源添加/删除 label 2. kubectl 重启 deployment&#xff08;滚动更新&#xf…

浆果行业调查:到2026年市场将达到515亿美元

浆果是一种流行的水果类别&#xff0c;包括各种水果&#xff0c;例如草莓、蓝莓、覆盆子、黑莓等。它们以其高营养价值、独特风味和烹饪应用的多功能性而闻名。近年来&#xff0c;由于人们越来越意识到食用浆果对健康有益&#xff0c;因此对浆果的需求一直在上升&#xff0c;预…

英飞凌TC3xx之一起认识GTM(十)详细说说GTM子模块TIM(架构)

英飞凌TC3xx之一起认识GTM(十)详细说说GTM子模块TIM(架构) 1 TIM简介1.1 输入源选择寄存器INPUTSRCx1.2 外部捕捉源选择寄存器 EXTCAPSRCx2 TIM通道2.1 TIM通道架构2.2 TIM通道模式3 总结编者话:GTM的定时器输入模块TIM是经常被使用的模块,因为它简单易用。它可以接入多种…

论文系列之-Mixtral of Experts

Q: 这篇论文试图解决什么问题&#xff1f; A: 这篇论文介绍了Mixtral 8x7B&#xff0c;这是一个稀疏混合专家&#xff08;Sparse Mixture of Experts&#xff0c;SMoE&#xff09;语言模型。它试图解决的主要问题包括&#xff1a; 1. 提高模型性能&#xff1a;通过使用稀疏混…

改进的yolov5目标检测-yolov5替换骨干网络-yolo剪枝(TensorRT及NCNN部署)

YOLOv5改进点 2022.10.30 复现TPH-YOLOv5 2022.10.31 完成替换backbone为Ghostnet 2022.11.02 完成替换backbone为Shufflenetv2 2022.11.05 完成替换backbone为Mobilenetv3Small 2022.11.10 完成EagleEye对YOLOv5系列剪枝支持 2022.11.14 完成MQBench对YOLOv5系列量化支持…

【开源】基于JAVA、微信小程序的音乐平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示 四、核心代码4.1 查询单首音乐4.2 新增音乐4.3 新增音乐订单4.4 查询音乐订单4.5 新增音乐收藏 五、免责说明 一、摘要 1.1 项目介绍 基于微信小程序JAVAVueSpringBootMySQL的音乐平台&#xff0c;包含了音乐…

Hive 日期处理函数汇总

Hive 日期处理函数汇总 最近项目处理日期操作比较繁杂,使用Hive的日期函数也较频繁 1. 加减日期 date_add(‘日期字符串’,int值) :把一个字符串日期格式加n天,n为int值 select date_add(‘2023-12-31’,7); 结果: 2024-01-07 date_sub(‘日期字符串’,int值) :把一个字符串…

IPV6学习记录

IPV6的意义 从广义上来看IPV6协议包含的内容很多: IPV6地址的生成与分配 IPV6的报头的功能内容 IPV4网络兼容IPV6的方案 ICMPv6的功能(融合了arp和IGMP功能) IPV6的路由方式 ipv6的诞生除了由于ipv4的地址枯竭外&#xff0c;很大程度上也是因为ipv4多年的发展产生了很多…

数字化工厂产品推荐 带OPC UA的分布式IO模块

背景 近年来&#xff0c;为了提升在全球范围内的竞争力&#xff0c;制造企业希望自己工厂的机器之间协同性更强&#xff0c;自动化设备采集到的数据能够发挥更大的价值&#xff0c;越来越多的传统型工业制造企业开始加入数字化工厂建设的行列&#xff0c;实现智能制造。 数字化…