动态规划(算法)---02.斐波那契数列模型_三步问题

题目链接:

面试题 08.01. 三步问题 - 力扣(LeetCode)icon-default.png?t=O83Ahttps://leetcode.cn/problems/three-steps-problem-lcci/description/

一、题目解析

题目:

题目讲解:

我们先举例查看规律:

第一台阶:我们从0台阶上到第一台阶,只需一步,就可以上去,所以只有一种上法

第二台阶:我们既可以从0台阶两步上到第二台阶,也可以先一步上第一台阶,再一步上到第二台阶,所以有两种

第三台阶:我们首先可以从0台阶三部上到第二台阶,其次可以先两步上第二台阶,再一步上第三台阶,同样也可以先一步上到第一台阶,再两步上到第二台阶,最后是一步一步上到第三台阶,总共有四种上去的方法。

那这里有没有什么规律呢?

  • 我们已经知道上第一台阶只有一种方法,上第一台阶后我们可以再跨两步上到第三台阶,这便成为了上第三台阶的一种方式!
  • 同样,我们知道上第二台阶有两种方法,这两种方法再跨一步就可以上到第三台阶,这不就成为了上第三台阶的两种方式了嘛
  • 第四种方法是从0台阶跨三步,这里没有明显的规律,我们接着看第四台阶

第四台阶:根据我们从第三台阶发现的一点规律,我们在这里观察一下

首先,我们要清楚,我们最高只能走三步,也就是想走三步我们只能从第一台阶走

  • 我们已经知道上第一台阶有一种方法,那上到第一台阶后再跨三部到第四台阶,就是我们上第四台阶的一种方式。
  • 同样,我们知道上第二台阶有两种方法,这两种方法再跨两步可以上到第四台阶,这不就成为了我们上第四台阶的方式了嘛。
  • 最后,上第三台阶有三种方法,那这三种方法再跨一步可以上到第四台阶,就是我们上到第四台阶的四种方式。

我们可以发现,上第四台阶的方法是上前面三个台阶的方法之和:1+2+4=7

综上,我们已经发现规律:从第四台阶开始,上每一台阶的方法是上前面三个台阶的方法之和

二、算法原理

1、状态表示

我们在状态标识的时候,一般都会创建一个数组dp,也就是我们所说的dp表,我们要做的就是把每一个状态的值填入这个表内,最终这个表内的某一个值可能就是我们要返回的值。 

  状态简单理解就是dp表内某一个值代表的含义。

  我们通常选择以一个位置为开始为开始或者为结尾

如何确定状态表示

  • 题目要求

   简单的题目里一般会给出

  • 经验+题目要求

  越学越深入,动态规划也是熟能生巧,在题目中没有明显给出的时候,我们就要凭借自己做题的经验来确定,所以就需要我们大量的做题。

  • 分析问题的过程中,发现重复子问题

分析问题的过程中把重复子问题抽象成我们的状态表示,这个更难理解,一切的基础都是我们先对动态规划算法熟练运用。我也不懂,我们慢慢来。 


那我们这道题的状态表示应该是什么呢?

根据我们对题目的了解,题目让我们求上到第n台阶的方法有多少,那我们创建一个数组dp,让dp[n]表示我们到达第n台阶的方法有多少。 

2、状态转移方程

 确定状态表示之后我们就可以根据状态标识推出状态转移方程

  状态转移方程是什么?

不讲什么复杂的,简单来说状态转移方程就是    dp[i]等于什么 dp[i]=?

  这个就是状态转移方程,我们要做的,就是推出dp[i]等于什么

  我们根据状态表示再结合题目+经验去推理转移方程,这一步也是我们整个解题过程中最难的一步

  我们在这道题先简单了解下什么是状态转移方程,之后比较难的题目再细推

 根据我们在题目解析中发现的规律:从第四台阶开始,上每一台阶的方法是上前面三个台阶的方法之和

 我们可知状态转移方程为:dp[i]=dp[i-1]+dp[i-2]+dp[i-3]

3、初始化

 我们创建dp表就是为了把他填满,我们初始化是为了防止在填表的过程中越界或者其它小的错误

怎么谈越界?

当i等于1时,dp[i-2],dp[i-3]都是越界,根本没有这个台阶,所以我们要进行初始化。

我们这道题也可以知道,规律是从第四台阶开始的,所以我们初始化前三台阶,是为了后面更好的进行

初始化:dp[1]=1 dp[2]=2 dp[3]=4

注:这里的下标没有错,我们为了做题更好理解,再对数组dp进行定义时会比台阶数多1,这样下标就与台阶对应,更好的理解!

4、填表顺序

注意填表顺序,是因为我们需要在填当前状态的时候,所需要的状态已经计算过了

  这个意思就是,我们在填状态dp[4]的时候,我们就已经知道其所需要的dp[1]、dp[2]、dp[3]状态的值了, 那假如我们直接填dp[4],可其所需要的状态dp[3]我们还没填,所以就计算不出来我们当前状态dp[4]的值,所以填表顺序也是需要考虑的一项

  这道题的填表顺序就是我们需要从状态dp[4]开始,依次填表。
                        

5、返回值

返回值就是我们最后需要求出的值,在这里也就是我们我们的数组dp的最后一个数dp[n]。返回值一般通过题目要求和状态表示来判断出来。

  以上就是我们算法原理的五步,这五步完成,其实我们就已经可以解题了。

三、编写代码

class Solution {
public:
    int waysToStep(int n) {
//细节问题
        const int Mod=1e9+7;
        if(n==1||n==2)
        {
            return n;
        }
        if(n==3)
        {
            return 4;
        }
//1、创建dp表
        vector<int> dp(n+1);
//2、初始化
        dp[1]=1;dp[2]=2;dp[3]=4;
//3、填表
        for(int i=4;i<=n;i++)
        {
            dp[i]=((dp[i-1]+dp[i-2])%Mod+dp[i-3])%Mod;
        }
//4、返回值
        return dp[n];
    }
};

 问题解释:

  •  细节1:我们需要模上1e9+7,否则数太大会被不通过,注意模的细节,两个的和先模,模完与另外一个数相加继续再模一次.

  • 细节2:因为第一、二、三台阶没有规律,不能进入填表,所以先检查台阶数,如果是一、二、三台阶,那么就返回其对应的方法数即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值