《LeetCode 1137 第N个泰波那契数 和 LeetCode 三步问题》

一、题目

二、做题思路

2.1 状态表示(核心基础)

状态表示即明确 dp 表中每个元素所代表的含义。其来源通常有三:直接依据题目要求 、结合经验对题目进行抽象、或在分析过程中提炼重复子问题 。本题中,题目已明确要求:数组下标 i 对应第 i 个泰波那契数,因此我们定义 dp[i] 表示第 i 个泰波那契数的值 。这是后续推导的基石,必须首先确定。

2.2 状态转移方程(关键难点)

状态转移方程描述了 dp[i] 与前面若干状态之间的递推关系 ,来源于题目给出的递推公式。本题直接依据泰波那契数列的定义:

dp[i] = dp[i-1] + dp[i-2] + dp[i-3](其中 i ≥ 3) 。

该方程将大问题拆解为规模更小的子问题 ,是整个动态规划过程的核心纽带。

2.3 初始化(边界防护)

初始化是为了保证填表过程中数组访问不越界 ,同时为递推提供起始条件 。由于状态转移方程需要用到前三个状态,当 i < 3 时无法通过方程计算,因此必须单独给出初始值。本题题目已明确:

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

这些初始值是递推的**"种子"** ,是正确计算的必要前提。

2.4 填表顺序(递推方向)

填表顺序取决于当前状态所依赖的前驱状态 ,必须保证计算某一状态时,其所需的所有前置状态均已就绪 。本题中,dp[i] 依赖 i-1、i-2、i-3(均小于 i),因此采用 从左到右 (即下标从小到大)的顺序依次填充 dp 表,可确保每次计算时所需数据已经完备。

2.5 返回值(目标映射)

返回值即最终需要向调用者 输出的结果,由题目要求与状态表示 共同决定。本题要求返回第 n 个泰波那契数,而 dp[n] 正好表示该值,因此直接返回 dp[n] 。若 n 小于初始边界,则直接返回对应的初始值,避免越界访问。

三、代码

cpp 复制代码
#include <vector>

using  namespace std;

class Solution {
public:
    int tribonacci(int n)
    {
        //3.初始化
        if (n == 0) return 0;
        if (n == 1 || n == 2) return 1;

        vector<int> dp(n + 1);//1.状态表示,一个下标对应一个Tn元素

        //3.初始化dp表
        dp[0] = 0, dp[1] = 1, dp[2] = 1;

        //2.状态转移方程 dpn = dpn-1 + dpn-2 + dpn-3
        //4.填表顺序
        for (int i = 3; i <= n; i++)
        {
            dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
        }

        //5.返回值
        return dp[n];
    }
};

四、流程图

五、题目

六、做题思路

6.1 状态表示(核心基础)

本题要求计算到达第 i 级台阶 的所有不同走法总数。因此定义 dp[i] 表示从地面(第 0 级)走到第 i 级台阶的方法数 。该定义直接来源于题目要求,且以位置为结尾 进行统计,是后续推导的出发点。

6.2 状态转移方程(关键难点)

小孩一次可以上 1 阶、2 阶或 3 阶 ,那么到达第 i 级台阶的最后一步 可能来自 i-1、i-2 或 i-3。由于这三种方式是互斥且完备 的,所以总方法数等于三者之和:

dp[i] = dp[i-1] + dp[i-2] + dp[i-3] (其中 i ≥ 4)。

同时,根据示例可验证初始值:dp[1]=1、dp[2]=2、dp[3]=4,与递推公式吻合。

6.3 初始化(边界防护)

递推公式依赖前三个状态,因此 i=1,2,3 必须手动赋值 :

dp[1] = 1 (仅 1 步),dp[2] = 2 (1+1 或 2),dp[3] = 4 (1+1+1、1+2、2+1、3)。

此外,题目提示结果可能很大,需对 100000007 (即 1e8+7)取模,每次相加后及时取模,防止溢出。

6.4 填表顺序(递推方向)

计算 dp[i] 必须依赖 dp[i-1]、dp[i-2]、dp[i-3],这些下标均小于 i。因此必须从左到右 (即下标从小到大)依次填充 dp 表,保证每个状态计算时,其所有前置状态均已就绪。

6.5 返回值(目标映射)

题目要求返回第 n 级台阶的走法数 ,而 dp[n] 正表示该值,因此直接返回 dp[n] 。若 n 在初始范围内(1~3),则直接返回对应的初始化值,无需进入递推循环,避免越界访问。

七、代码展示

cpp 复制代码
#include <vector>
using namespace std;
class Solution {
public:
    int waysToStep(int n)
    {
        //处理边界情况
        if (n == 1) return 1;
        if (n == 2) return 2;
        if (n == 3) return 4;

        const int Mod = 1e9 + 7;//模数 

        //1.创建dp表
        vector<int> dp(n + 1);
        //3. 初始化
        dp[1] = 1, dp[2] = 2, dp[3] = 4;

        //2.状态转移方程
        for (int i = 4; i <= n; i++)
        {
            //4. 填表顺序(从左到右)
            dp[i] = ((dp[i - 3] + dp[i - 2]) % Mod + dp[i - 1]) % Mod;
        }
        //5. 返回值     
        return dp[n];
    }
};

八、流程图

相关推荐
choumin40 分钟前
C++中万能引用与std::forward的作用和用法
c++·万能引用·std forward
下一站春风里2 小时前
位运算完整学习笔记:按位与(&)+ 异或(^)
开发语言·c++·算法
DRobot2 小时前
【机械制图与CAD实战(二十五)】螺纹的表示方法
算法·机械制图
用户老李2 小时前
卡尔曼滤波自学教程 10:无迹卡尔曼滤波(UKF)
算法
深圳市益普科技有限公司3 小时前
半导体良率管理YMS:良率与设备参数的相关性,先拉哪几组数据
人工智能·python·算法
努力努力再努力wz4 小时前
【C++高阶系列】C++20 协程底层原理:函数为什么能暂停?从状态机到 Task,彻底串起挂起、恢复与协程调度
开发语言·c++·c++20·1024程序员节
程序员清风5 小时前
算法题中的边界条件、测试与调试
开发语言·算法·kotlin
划破黑暗的第一缕曙光5 小时前
[C++]:4.模板
c++·template·模板·函数模版·类模版
十五年专注C++开发5 小时前
pybind11:一个跨C++和Python平台的编程库
开发语言·c++·python·pybind11
CodeYp20195 小时前
第11讲:stack 和 queue
开发语言·c++·queue·stack