动态规划怎么学?
学习一个算法没有捷径,更何况是学习动态规划,
跟我一起刷动态规划算法题,一起学会动态规划!
1. 题目解析
题目链接:1137. 第 N 个泰波那契数 - 力扣(Leetcode)
我们根据题目给的条件:
Tn+3 = Tn + Tn+1 + Tn + 2,也就是:Tn = Tn - 1 + Tn - 2 + Tn - 3
可以知道,第n个泰波那契数实际上就是他前三个数的和。
2. 算法原理
1. 状态表示
一般来说,我们会先创建一个数组作为dp表,
将这个dp表填满,而答案就在这个表上的某一个位置,
而状态表示的意思就是,表上的一个值表示的含义。
不说这些虚的,那我们该怎么得出状态表示呢?
1. 根据题目要求
2. 根据我们的经验 + 题目要求
3. 分析问题的过程中,发现重复的子问题
不过这道题目比较简单,我们能直接根据题目要求得出状态表示:
dp[ i ] 表示:第 i 个泰波那契数。
2. 状态转移方程
那状态转移方程是什么呢?
实际上就是:
dp[ i ] 等于什么。
这道题比较简单,题目直接把状态转移方程的公式直接给我们了,
所以 dp[ i ] 就等于:
dp[ i ] = dp[ i - 1 ] + dp[ i - 2 ] + dp[ i - 3 ]
3. 初始化
初识化的功能就是:
保证填表的时候不越界。
而这道题也非常贴心的给我们了:
他告诉我们:T0 = 0,T1 = 1,T2 = 1,
那我们只需要初始化:dp[ 0 ] = 0,dp[ 1 ] = 1,dp[ 2 ] = 1,即可。
4. 填表顺序
填表顺序是为了:填写当前状态的时候,所需的状态已经计算过了,
所以这道题我们的填表顺序就是从左往右填。
5. 返回值
实际上返回值就是返回题目要求的值啦,这道题要返回的就是:dp[ n ]
3. 代码编写
先来看题目接口:
class Solution { public: int tribonacci(int n) { } };
我们就按照刚刚学习算法原理的顺序写代码:
class Solution { public: int tribonacci(int n) { // 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回值 // 处理边界问题 if(n == 0) return 0; if(n == 1 || n == 2) return 1; vector 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]; } };
根据我们的四部走,然后处理了一下边界的问题,然后就通过了:
4. 空间优化
我们刚开始学习动态规划的时候,最重要的是怎么把这道题做出来,
而不是想着怎么优化,所以之后不会重点来讲这个,
不过现在趁着这道题比较简单,就来优化一下,欺负一下这道题。
一般动态规划的空间优化都是用滚动数组优化,
当我们在填一个dp表的时候,只需要使用前面若干个状态,而其他状态不再需要的时候,
我们就可以使用滚动数组进行优化:
class Solution { public: int tribonacci(int n) { //空间优化 // 处理边界问题 if(n == 0) return 0; if(n == 1 || n == 2) return 1; int a = 0, b = 1, c = 1, d = 0; for(int i = 3; i <= n; i++) { d = a + b + c; //滚动操作: a = b; b = c; c = d; } return d; } };
这样空间消耗就从O(N)变成O(1)了。
写在最后:
以上就是本篇文章的内容了,感谢你的阅读。
如果感到有所收获的话可以给博主点一个赞哦。
如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~