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

第 N 个泰波那契数(easy)

题目链接:

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

题目解析

注意,我们题目是泰波那契数,不是斐波那契数.

注意一下 Tn的定义,我们把n直接给赋值为0,此时变化为T3 = T0+ + T1 + T2 也即是 我们 给定一个数据 N, 那么TN等于前面三项之和.只要题目中给出我们前三项,那么此时我们就可以推导出第四,五…项.

image-20230803204818326

算法原理

由于我们这里是第一个题目,我们先说一下我们之后要用到的名词.

什么是动态规划,一般而言,我们创建一个一维或者二维数组,我们把他们称之为dp数组,后面我们想办法把这个表给填满,这个数组里面的某一个元素的值就是我们的答案.这个可以作为我们动态规划的流程.

状态表示: 对于数组里面的某一个位置的值可以理解为一个状态表示,他代表了一定含义.我们这里不说状态表示定义是什么,就说怎么得到这个值,毕竟这个名词实在是太严谨,我们先初步理解,有兴趣的朋友可以仔细的去查一下.

转台转移方程,如何得到一位置的确定值就是我们寻找状态转移方程的过程,一般而言,我们得到状态转移方程的思想有下面三个.

  • 题目要求
  • 题目要求+经验
  • 分析问题过程中发现重复子问题

状态表示

这个很简单,我们可以把数组中的元素的值作为泰波那契数列的结果.

dp[i]: 表示 Ti的值

image-20230803211344206

状态转移方程

这个很简单,题目上已经给了Ti = Ti-1+Ti-2+Ti-3

初始化

初始化的目的就是保证不越界,例如本题就是dp[i]要确定值,i必须从3开始出发,毕竟要找到前面三个元素的值,所以初始化为.

dp[0] = 0, dp[1] = 1,dp[2] = 1;

填表顺序

填表的顺序和我们逻辑顺序要一致,例如本题我们dp[i]是要看前面的元素,所谓我们这里从左向右.

返回值

这个看题目要求和我们的状态表示.题目要求我们返回第n个泰波那契数,我们dp[i]表示第n个泰波那契数,所以返回dp[n].

编写代码

class Solution {
public:int tribonacci(int n){if(n == 0)return 0;if(n == 1 || n == 2)return 1;// 我们要返回 dp[n]std::vector<int> dp(n+1);// 初始化dp[0] = 0;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];}
};	

image-20230803212927946

空间优化

由于我们是第一题,先把动态规划的完整流程给大家演示一下,后面我们就不谈空间优化的事情了.

对于动规的题目我们一般是使用滚动数组进行优化的,大家看一下这道题目.

image-20230803213332450

我们可以发现我们求dp[i]的时候仅仅需要前面三个元素的值就可以了,像这些dp[i]仅仅需要前面若干的状态的情况我们可以使用滚动数组,例如我们可以定义一个容量为四个元素的数组,依次更新就可以了.

这里说一下优化的结果,一般空间复杂度可以降低一个数量级,例如O(N)的变化为O(1).

class Solution
{
public:int tribonacci(int n){if (n == 0)return 0;if (n == 1 || n == 2)return 1;int a = 0;int b = 1;int c = 1;int d = 0;for (int i = 3; i <= n; i++){d = a + b + c;a = b;b = c;c = d;}return d;}
};

image-20230803214112014

三步问题(easy)

题目链接:

面试题 08.01. 三步问题

题目描述:

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

示例1:

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

示例2:

 输入:n = 5输出:13

题目解析

给定一定数量的台阶,例如10个.其中小孩子它可以一次跳1个台阶,2个台阶,3个台阶.问问我们我们总共有多少种方式可以到达第10个台阶.分析一下示例.

n = 3时, 我们可以这样跳.

方式1 : 1 1 1       每一次跳一个台阶
方式2 : 1 2         第一次跳一个, 第二次跳两个
方式3 : 2 1         第一次跳两个, 第二次跳一个
方式4 : 3           直接跳三个

算法原理

状态表示

这个需要我们的经验了,和数学相关的.我们让dp[i]表示到达第i个台阶我们的方法数.

状态转移方程

dp[i]表示到达第i个台阶的方法数,那么此时我们想如歌可以到达第i给台阶,这里很简单,有三个方式

i-1 下一步跳一个台阶
i-2 下一步跳两个台阶
i-3 下一步跳三个台阶

那么此时dp[i]分别就是这三个方式的和,也就是我们到达i-1和i-2以及i-3的方法数之和,正好dp[i]表示到达第i个台阶的方法数.

i-1 下一步跳一个台阶   dp[i-1] 
i-2 下一步跳两个台阶   dp[i-2]
i-3 下一步跳三个台阶   dp[i-3]dp[i] = dp[i-1]+ dp[i-2]+ dp[i-3]

初始化

这里存在i-3,所以我们需要进行初始化.

dp[0] = 0, dp[1] = 1,dp[2] = 2; dp[3] = 4;

这里需要说一下,我们也是可以这样初始化的

dp[0] = 1, dp[1] = 1,dp[2] = 2;

这样初始化的意思主要是为了满足dp[3]的求值.

填表顺序

和前面一样从左先右.

返回值

题目要求给定一个n,求到达第n个台阶的方法数,这里就是dp[n]

编写代码

class Solution
{
public:int waysToStep(int n){if (n == 1)return 1;if (n == 2)return 2;std::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] + dp[i - 3];return dp[n];}
};

image-20230803221139927

这是因为题目中说了数据可能会溢出,所以这里我们两个数相加的时候需要处理一下.

class Solution
{
public:int waysToStep(int n){if (n == 1)return 1;if (n == 2)return 2;const int MOD = 1e9 + 7;std::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]) % MOD + dp[i - 3]) % MOD;return dp[n];}
};

image-20230803220929446

使用最小花费爬楼梯(easy)

题目链接:

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 。

题目解析

对于给定的数组,我们站在某一个确定的位置,然后花费该位置元素的代价后可以向后面移动一步或者两步,求我们到达楼梯顶部的花费.

此时我们需要知道的是我们的初始位置可以是从下标0或者1开始的.例如示例一数组为 [10,15,20],我们这里从下标1开始,直接跳两步就可以完成了.

在这道题中,数组内的每一个下标 [0, n - 1] 表示的都是楼层,而顶楼的位置其实是在 n 的位置!!!

算法原理

这里我们是题目要求+经验解题.我们用两个方法来解题.

解法一

状态表示

dp[i]表示以i位置为终点花费的最少的花费,注意:到达 i 位置的时候, i 位置的钱不需要算上

状态转移方程

可以到达i位置的有i-1和i-2位置,我们求他们花费的交小值,注意是我们计算较小值的时候是需要加上我们的代价的

dp[i] = min(dp[i-1]+const[i-1],dp[i-2]+const[i-2]).

初始化

这里的初始化有点意思,我们这里有i-2,所以我们这里初始化前两个.我们又可以知道我们初始的时候是可以选择0或者1的,那么0或者1位置的代价是0.所以我们这样做:dp[0] = 0,dp[1] = 0;

填表顺序

从左先右开始填.

返回值

我们要求的是到达n位置的最小花费,此时返回dp[n].

编写代码

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

image-20230805200341962

解法二

状态表示

dp[i]表示以i位置为起点到达终点时需要花费的最少的花费.

状态转移方程

i位置为开始,此时我们可以跳到i+1或者i+2位置,如果i+1位置要跳到终点,按照我们的状态定义,此时应该是dp[i+1],同理i+2是dp[i+2].

我们知道,如果想要跳到i+1位置和i+2位置,我们在i位置是要花费代价的,此时这里的方程是.

dp[i] = min(dp[i+1], dp[i+2]) + const[i];

初始化

这里我们需要依赖i+1或者i+2的值,此时需要初始化dp[n],按照dp[i],我们从n位置到达n位置的花费是0.,这里我们需要注意的我们依赖i+2位置,这个时候我们需要从n-2位置开始填,那么问题来了,dp[n-1]填什么,这个很简单,他跳一步就可以到顶层,那么就是dp[i-1] = const[i-1]

填表顺序

这里是从右向左填.

返回值

按照状态定义,我们是从0位置或者1位置开始出发,到达顶部的最小花费,此时返回dp[0]和dp[1]的较小值.

编写代码

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

image-20230805200341962

解码方法(medium)

题目链接:

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->a,2->b…26->z.注意一下,我们1可以映射为a,但是01确实不可以的.

算法原理

状态表示

题目要求+经验.

dp[i]: 以i位置为结尾,我们可以映射字符串的个数.

状态转移方程

这里分为两类.

i位置的字符单独作为一个映射, 如果可以映射,那么此时就是dp[i] = dp[i-1]. 注意我们求的是个数,这里是不能加1的.

i位置和前面一个字符进行映射,如果可以话,此时dp[i] = dp[i-2].

这两个情况都是可以的,所以我们的状态方程的结构是dp[i] = dp[i-1]+dp[i-2],具体的分析如下.

image-20230805203637523

初始化

需要用到i-1和i-2,这里我们需要初始化dp[0]和dp[1],上面我们已经用过几次,这里我们换一个初始化方法.我们发现dp[0]比较好初始化,这里只需要关注dp[1],我们申请空间的时候额外申请多申请一个作为辅助节点,看下面.

image-20230805204615052

对于str[1]位置而言,如果单独转化,此时只需要关注前面一个,也就是dp[1].如果和str[0]组合,此时需要知道的时如果可以组合成功,那么dp[2] = dp[0],那么dp[0]应该被初始化1.需要注意的,我们添加辅助节点之后,我们访问str的元素是需要下标适配的.

填表顺序

从左先右.

返回值

返回dp[n],之所以返回n位置的值,是因为我们添加了辅助节点.

编写代码

class Solution {
public:int numDecodings(string s) {int n = s.size();vector<int> dp(n+1, 0);dp[0] = 1;for(int i = 1; i <= n; i++){// 单独一个 i-1 需要匹配if(s[i-1] != '0') dp[i] = dp[i-1];// 和前面一个字符匹配if(i-2>=0 && s[i-2]!='0' && (10*(s[i-2]-'0')+s[i-1]-'0') < 27)dp[i] += dp[i-2];}return dp[n];}
};

image-20230805205328365

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

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

相关文章

k8s-服务发现service和ingress

回到目录 service用于集群内部应用的网络调用&#xff0c;处理东西流量 ingress用于集群外部用户访问内部服务&#xff0c;处理南北流量 一 kube-proxy三种代理模式 kubernetes集群中有三层网络&#xff0c;一类是真实存在的&#xff0c;例如Node Network、Pod Network,提供真…

Node.js究竟是什么?初学者指南

如果你正在考虑使用JavaScript进行后端开发&#xff0c;你会听到“Node.js”这个术语。Node通常与开发功能强大的web服务器联系在一起。 但 Node.js 究竟是什么&#xff1f;它是和 Angular 一样的 JavaScript 框架吗&#xff1f;它是一种编程语言吗&#xff1f;它是 JavaScrip…

中国中医中药元宇宙 中药材价格缘何“狂飙”

◇相比去年同期&#xff0c;有超200个常规品种涨幅高于50%&#xff0c;25个常用大宗药材涨幅超200%&#xff0c;个别品种甚至涨价4至9倍 ◇在中药材价格普遍高涨的情况下&#xff0c;部分市场仓库库存数量也较多&#xff0c;出现囤积居奇倾向 ◇“不少游资和热钱涌入中药材市场…

Spring Boot + Vue3前后端分离实战wiki知识库系统<十一>--文档管理功能开发三

文档内容的显示&#xff1a; 在上一次Spring Boot Vue3前后端分离实战wiki知识库系统&#xff1c;十&#xff1e;--文档管理功能开发二文档管理模块还差文档的显示木有完成&#xff0c;所以接下来先将这块模块给收尾了。 增加单独获取内容的接口&#xff1a; 概述&#xff…

设计模式、Java8新特性实战 - List<T> 抽象统计组件

一、背景 在日常写代码的过程中&#xff0c;针对List集合&#xff0c;统计里面的某个属性&#xff0c;是经常的事情&#xff0c;针对List的某个属性的统计&#xff0c;我们目前大部分时候的代码都是这样写&#xff0c;每统计一个变量&#xff0c;就要定义一个值&#xff0c;且…

ATTCK实战系列-红队评估 (红日靶场3)Vulnstack三层网络域渗透靶场

文章目录 环境配置靶场介绍靶场设置 外网渗透信息收集端口扫描目录扫描 漏洞发现与利用获取ssh账号密码&#xff0c;登录centos 提权 内网渗透建立代理内网信息收集smb暴破&#xff0c;获取本地管理员密码 横向移动使用psexec模块上线msf 环境配置 靶场介绍 靶场地址 http:/…

剑指Offer 20.表示数值的字符串

20.表示数值的字符串 题目 官方地址 代码&#xff08;正则表达式&#xff09; public boolean isNumeric (String str) {if (str null || str.length() 0)return false;return new String(str).matches("[-]?\\d*(\\.\\d)?([eE][-]?\\d)?"); }在给定的代码…

PCIE链路信息

目录 简介&#xff1a; 目的&#xff1a; 详情&#xff1a; 简介&#xff1a; PCIe有很多寄存器&#xff0c;也有很多控制&#xff0c;包括链路状态信息&#xff0c;上一节我们讲到了PCie的链路训练&#xff0c;这节文章将继续学习PCIe相关知识。 目的&#xff1a; 从设计…

【Python从小白到高手】---函数基础

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【Python小白从入门到精通】&#x1f388; 本专栏旨在分享学习Python的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录…

iPhone 6透明屏是什么?原理、特点、优势

iPhone 6透明屏是一种特殊的屏幕技术&#xff0c;它能够使手机屏幕变得透明&#xff0c;让用户能够透过屏幕看到手机背后的物体。 这种技术在科幻电影中经常出现&#xff0c;给人一种未来科技的感觉。下面将介绍iPhone 6透明屏的原理、特点以及可能的应用。 iPhone 6透明屏的原…

本地 shell无法连接centos 7 ?

1、首先检查是否安装ssh服务&#xff1b; yum list installed | grep openssh-server# 没有安装尝试安装下 yum install openssh-server 2、检查ssh服务是否开启 systemctl status sshd.service# 未开启&#xff0c;开启下 systemctl start sshd.service # 将sshd 服务添…

socker套接字

1.打印错误信息 2.socketaddr_in结构体 结构体&#xff1a; &#xff08;部分库代码&#xff09; (宏中的##) 3.manual TCP: SOCK_STREAM &#xff1a; 提供有序地&#xff0c;可靠的&#xff0c;全双工的&#xff0c;基于连接的流式服务 UDP: 面向数据报

406 · 和大于S的最小子数组

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a;同向双指针 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 class Solution { public:/*** param nums: an array …

【maven】构建项目前clean和不clean的区别

其实很简单&#xff0c;但是百度搜了一下&#xff0c;还是没人能简单说明白。 搬用之前做C项目时总结结论&#xff1a; 所以自己在IDE里一遍遍测试程序能否跑通的时候&#xff0c;不需要clean&#xff0c;因为反正还要改嘛。 但是这个项目测试好了&#xff0c;你要打成jar包给…

element-tree-line el-tree 添加结构线 添加虚线

概览&#xff1a;给element组件添加上虚线&#xff0c;通过使用插件element-tree-line 参考连接&#xff1a; 参考别人的博客 安装插件&#xff1a; # npm npm install element-tree-line -S # yarn yarn add element-tree-line -S main.js全局注册引入插件&#xff1a; imp…

Python批量查字典和爬取双语例句

最近&#xff0c;有网友反映&#xff0c;我的批量查字典工具换到其它的网站就不好用了。对此&#xff0c;我想说的是&#xff0c;互联网包罗万象&#xff0c;网站的各种设置也有所不同&#xff0c;并不是所有的在线字典都可以用Python爬取的。事实上&#xff0c;很多网站为了防…

Linux文本三剑客---grep、sed、awk

目录标题 1、grep1.1 命令格式1.2命令功能1.3命令参数1.4grep实战演练 2、sed2.1 认识sed2.2命令格式2.3常用选项options2.4地址定界2.5 编辑命令command2.6用法演示2.6.1常用选项options演示2.6.2地址界定演示2.6.3编辑命令command演示 3、awk3.1认识awk3.2常用命令选项3.3awk…

向表中随机插入字符串数据

已知表 向该表中插入指定次数的随机字符串&#xff1a; 代码如下: DROP PROCEDURE sc //CREATE PROCEDURE sc(num INT) BEGIN DECLARE str VARCHAR(26) DEFAULT "abcdefghijklmnopqrstuvwxyz"; DECLARE cnt INT DEFAULT 0; DECLARE startIndex INT DEFAULT 1; DE…

msvcp120.dll丢失的解决方法(亲测可修复方的法)

在运行某些软件的时候&#xff0c;计算机提示msvcp120.dll丢失&#xff0c;无法打开运行软件。在第一次遇到这个问题的时候&#xff0c;相信很多人都不知道是怎么回事。下面小编把msvcp120.dll是什么以及如何解决这个问题的详细方法给大家科普一下。 问题描述&#xff1a; 在使…

Ubuntu安装MySQL 8.0与Navicat

目录 Ubuntu安装MySQL 8.0 1、更新软件包列表 2、安装 MySQL 8.0 3、启动 MySQL 服务 5、确保MySQL服务器正在运行 5、root 用户的密码 6、登录MySQL&#xff0c;输入mysql密码 7、MySQL默认位置 Ubuntu安装Navicat 1、下载 Navicat 2、额外的软件包 3、执行命令 U…