算法王冠上的明珠——动态规划之斐波那契数列问题

目录

[1. 什么是动态规划](#1. 什么是动态规划)

[2. 动态规划步骤](#2. 动态规划步骤)

状态表示

状态转移方程

初始化

填表顺序

返回值

[3. 例题讲解及具体代码](#3. 例题讲解及具体代码)

[3.1 LeetCode1137. 第 N 个泰波那契数](#3.1 LeetCode1137. 第 N 个泰波那契数)


这篇文章是我第一篇关于动态规划的,所以我会先从什么是动态规划说起。

1. 什么是动态规划

动态规划是一种通过将复杂问题分解为重叠子问题,并利用子问题的解来高效求解原问题的算法思想。它的核心是避免重复计算,通过存储中间结果(即 "记忆化")来优化时间复杂度。

其实简单来说就是通过前面的状态来定义后面的状态,比如说我们前面关于前缀和的文章其实就可以被归为动态规划的一种,只不过它比较简单,所以我把它放在了基础算法里面。

2. 动态规划步骤

做动态规划类题目的步骤就是下面这几步。

状态表示

状态表示就是我们数组对应的那个位置的值的含义,简单来说就是那个值代表着什么。比如说我们前面说的前缀和,那他的状态表示就是代表着原数组前面这些数的累加。

状态转移方程

状态转移方程就是根据上面的状态表示来得到的一个公式,比如说我们前面说的前缀和,它的状态转移方程就是dp[i]=dp[i-1]+nums[i]。

初始化

初始化的作用简单来说就是为了防止数组越界访问,所以我们在一开始会给dp表的一小部分值提前给好。方便我们后续计算。拿前缀和来说就是第0个位子我们会直接给0。

填表顺序

之所以我们要有填表顺序,是因为我们填当前位置的值会使用到前面的一些值,那么我们要确保前面的这些值都已经计算好了。

返回值

返回值就是返回题目要求的那个值。

接下来我们通过几道例题来了解这几个步骤。

3. 例题讲解及具体代码

3.1 LeetCode1137. 第 N 个泰波那契数

接下来我们来讲解下面这道题,题目意思也很简单,就是当前位置的值是由前面三个位置的值得来的。

所以在这道题里面它的状态表示就是当前位置值等于前面三个位置的值的和。

所以在这道题里面它的状态转移方程就是dp[i]=dp[i-1]+dp[i-2]+dp[i-3]。

它的初始化就是第0个位子设置为0,第一个和第二个位置设置为1。

填表顺序就是从前往后就好。

返回值就是第n个位置的值。

我们看下面这个代码,其实我们做动态规划的题目,只要可以把上面的这五步给写出来,那么代码的实现也就变的很简单了。

cpp 复制代码
class Solution {
public:
    int tribonacci(int n) {
        if(n==0) return 0;
        if(n==1||n==2) return 1;
        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];
    }
};

3.2 面试题 08.01. 三步问题

我们看下面这道题就稍微有一点点难了,要我们算的是小孩走到这n步时的方法。

状态表示:dp[n]表示走到当前位置时的方法数。

状态转移方程:这道题的状态转移方程稍微有点难,我们看下面这个图,0代表的是地板。然后我们到a就1种办法(一步),到b有2种(一步一步,两步),到c的方法有4种(一步一步一步,一步两步,两步一步,三步),接着我们就不用自己算了,因为按照题目的要求,从a,b,c位置可以走到d位置,所以我们这里直接就是d前面三个位置办法的和就好了。我一开始在做的时候是想着是前三个位置的办法数加上多少多少,后来经过尝试发现不是。因为我们可以这样去想如果a位置的值要加上多少多少的话,那么就会把b和c的一部分给计算进去了,会造成重复计算,所以我们不要去关心abc是怎么到d位置的,我们要记住每一个位置的值代表的是到该位置的方法数,而一个位置只有它前面的三个可以到,所以加上前面三个的方法数就好了。

PS:如果还是觉得不太理解的话,那么就画个图,把abc的方法都画出来,这样也可以理解。

初始化:在上面已经写了,到a就1种办法(一步),到b有2种(一步一步,两步),到c的方法有4种(一步一步一步,一步两步,两步一步,三步)。

填表顺序:由题可得是从前向后填表。

返回值:返回值就是n位置的方法数。

我们看,只要我们知道上面的那5个,那么代码就可以直接写出来了。

我们在dp[i-1]+dp[i-2]这里也模上了一个1000000007,是因为在这里也会过大。所以我们要先模一下。

cpp 复制代码
class Solution {
public:
    int waysToStep(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        if(n==3) return 4;
        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];
    }
};
相关推荐
TDengine (老段)1 小时前
TDengine 字符串函数 TO_BASE64 用户手册
android·大数据·服务器·物联网·时序数据库·tdengine·涛思数据
无敌最俊朗@8 小时前
力扣hot100-206反转链表
算法·leetcode·链表
Kuo-Teng8 小时前
LeetCode 279: Perfect Squares
java·数据结构·算法·leetcode·职场和发展
王哈哈^_^8 小时前
YOLO11实例分割训练任务——从构建数据集到训练的完整教程
人工智能·深度学习·算法·yolo·目标检测·机器学习·计算机视觉
檐下翻书1739 小时前
从入门到精通:流程图制作学习路径规划
论文阅读·人工智能·学习·算法·流程图·论文笔记
源码之家9 小时前
基于Python房价预测系统 数据分析 Flask框架 爬虫 随机森林回归预测模型、链家二手房 可视化大屏 大数据毕业设计(附源码)✅
大数据·爬虫·python·随机森林·数据分析·spark·flask
CoderYanger9 小时前
B.双指针——3194. 最小元素和最大元素的最小平均值
java·开发语言·数据结构·算法·leetcode·职场和发展·1024程序员节
TDengine (老段)10 小时前
什么是 TDengine IDMP?
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
小曹要微笑10 小时前
STM32各系列时钟树详解
c语言·stm32·单片机·嵌入式硬件·算法