系列文章目录
leetcode - 双指针问题_leetcode双指针题目-优快云博客
leetcode - 滑动窗口问题集_leetcode 滑动窗口-优快云博客
目录
前言
路漫漫其修远兮,吾将上下而求索;
大家可以先尝试自己做一下喔~
斐波那契数列模型
- 1137. 第 N 个泰波那契数 - 力扣(LeetCode)
- 面试题 08.01. 三步问题 - 力扣(LeetCode)
- 746. 使用最小花费爬楼梯 - 力扣(LeetCode)
- 91. 解码方法 - 力扣(LeetCode)
1、题1 第 N 个泰波那契数 :
1137. 第 N 个泰波那契数 - 力扣(LeetCode)

思考:
可以将泰波那契数看作是斐波那契数的加强版;
根据题意可知第n个泰波那契等于其前三个泰波那契数之和;
解法一:动态规划
动态规划的做题流程,一般会定义一个dp 表(dp 表通常是一个一维数组或者二维数组);一维数组的情况:先创建一个一维数组,该数组通常被称为dp 表,接下来就是填dp 表,其中的某一个值可能就是最后的结果;
我们可以使用动态规划来解决这道题,五个步骤:
1、确定一个动态表达式
2、根据该动态表达式来推导状态转移方程
3、初始化
4、填表顺序
5、返回值
a、状态表示
Q1: 什么是状态表示?
- dp 表中某一个位置所代表的含义;eg.dp[0] 存了一个值a,那么值a 便会代表一个特殊的含义,其中此含义就是状态表示;
Q2:状态表示是怎么样来的?
一般有三种方式可以来确定:
- 1、题目怎么要求,我们就怎么定义状态表示
- 2、经验 + 题目要求
- 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)
注:在本题中可以直接按照题干的要求去定义一个状态表示;本题的目标:返回第n个泰波那契数;
我们可以搞一个dp 表,让dp[0] 表示第0个泰波那契数,dp[1] 表示第1个泰波那契数……dp[i] 表示第i 个泰波那契数……我们只需要返回第n 个泰波那契数,即返回 dp[n];
b、状态转移方程
在本题中,我们需要思考的是:dp[i] 怎么求来?
推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题
本题十分明显由
可得:Tn = Tn-1 + Tn-2 + Tn-3 ;故而本题的状态转移方程为:dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
c、初始化
初始化的含义:保证填dp表(根据状态转移方程来调表)的时候不会发生越界;
Q1:为什么要保证不越界?
- 倘若用此处的状态转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]; 直接填表,那么 dp[0] = dp[-1] + dp[-2] + dp[-3] ,而 dp[-1] ,dp[-2] ,dp[-3] 就是越界访问;本题中的dp[0] 、dp[1]、dp[2]使用状态转移方程的时候均会发越界,所以这三个值需要单独进行初始化;而如何初始化取决于题干;
在本题中:![]()
d、填表顺序
Q:为什么要研究填表顺序?
- 为保证填写当前状态的时候所需要的状态已经计算好了;
在本题中,因为dp[i] = dp[i-1] + dp[i-2] + dp[i-3],即填表的时候需要借助于其前三个数据,所以填表顺序为从左往右;
d、返回值
返回结果: 结合题目要求+状态表示
本题干:
,所以我们返回 dp[n] 即可;
参考代码:
int tribonacci(int n)
{
//边界情况处理
if(n==0) return 0;
else if(n==1 || n==2) return 1;
//创建一维dp
//状态表示:dp[i]表示第i个泰波那契数
//状态转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
//初始化: dp[0]= 0 , dp[1] =1, dp[2] = 1;
//填表顺序: 从左往右
//返回值:dp[n]
vector<int> dp(n+1);
//初始化
dp[0]= 0 , dp[1] =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];
}
解法二:空间优化版本
注:此处空间优化的技巧只会在这道题以及接下来的背包问题中可用;
关于动态规划的空间优化,一般都是用流动数组的形式来优化;可以将时间复杂度为O(N^2)的动态规划优化成时间复杂度为O(N),将时间复杂度为O(N)的动态规划优化成时间复杂度为O(1);

可以发现,在求某一状态时,仅需要该状态前三个状态就可以求得到本状态;当我们依次从左往右求dp[i] 的时候,dp数组中太靠前的数据反而用不到,显然用不到的数据可以省去的。仅用该数组中有效的若干个状态便可以解决,像这样的情况,我们都可以用滚动数组来解决;创建三个变量进行”流动“,以维护所求状态的前三个状态;
Q:明明是利用变量在滚动的,为什么叫做”滚动数组“?
”滚动数组“只是一个名字而已,取这个名称只是为了统一叫法;
注:三个变量,在实现的时候还可以定义为 int[3] 的数组
动态规划解决斐波那契数列模型问题

最低0.47元/天 解锁文章
2888

被折叠的 条评论
为什么被折叠?



