动态规划(2)斐波那契数列模型——三步问题

大家好,今天带大家做一道动态规划入门级别的问题,三步问题。

一、题目解析

好,我们来看这道题,有一个小孩,它在上楼梯,这个楼梯有n阶台阶,小孩可以一次上1阶,也可以一次上2阶,也可以一次上3阶。现在让我们计算一下这个小孩子有几种上楼梯的方式。这个结果很大,因此我们在计算结果的时候需要取模。题目还是很简单的,那么我们来分析一下这个问题。

二、算法原理

我没有学动态规划的时候,第一次看到这道题的时候,其实很懵逼的,根本无从下手呀,第一感觉就是好抽象,有好多可能性,我怎么知道呢?不知道大家是不是这种想法。好,接下来带大家分析一下这道题。

第一个台阶:

我用0表示地平线,1、2、3、4就表示有几号台阶。好我们先来看,我们走到第一个台阶有几种方式?就一种呀,我直接从地平线走一步上到到第一个台阶上。一共有一种方式。

第二个台阶:

可以直接从地平线走一步上两个台阶到达第二个台阶。一共有一种方式。

我也可以从第一个台阶再走一步走一个台阶走到第二个台阶,就是从第一步的后面再加上一步就可以到达第二个台阶。一共有两种方式

第三个台阶:

可以直接从地平线走一步上三个台阶到达第三个台阶,此时方法数+1。

也可以从第一个台阶在走一步上两个台阶到达第三个台阶。其实就是我从第一步的方法后面在加一步就可以,走第一个台阶有一种方式,因此方法数在+1即可。

也可以从第二个台阶走一步上一个台阶走到第三个台阶。就是在走到第二步的每一种方法后面再加上一步,在走上一步就可以到达第三个台阶。走到第二个台阶有两种方法,因此此时方法数在+2即可。

因此上第三个台阶一共有四种方式。

第四个台阶:

可以从第一个台阶走一步上三个台阶到达第四个台阶,在到第一个台阶的方式上在多加一步,就可以到第四个台阶,到达第一个台阶只有一种方法,因此方法数+1

也有从第二个台阶上走一步上二个台阶到达第四个台阶,走到第二个台阶上有二种方式,在这两种方式的后面分别在走上一步,就ok了,此时方法数在+2。

也可以从第三个台阶走上一步上一个台阶到达第四个台阶,走到第三个台阶上有四种方式,在这四种方式的后面分别在走上一步,就ok了,此时方法数在+4。

此时上第四个台阶一共有七种方式

从上述分析中,我们可以发现一个什么东西?我们看上第四个台阶的方法数,是不是就是上前三个台阶方法的和呢?是不是就和我们上一道泰波那契那道题的状态转移方程一样呢?

如果你不信,你可以在自己推导一下第五个台阶的方式。

状态表示:

dp[i]:楼梯有i阶台阶,小孩子上楼梯总共有几种方式。这道题的状态表示怎么来的呢?其实就是根据题目要求得来的。这里提一下,数组的下标是从0开始的,因此,0号下标其实是没有意义的,因为没有0个台阶,所以我们开空间的时候要开n + 1个,然后0号位置直接空过,填表的时候从1号下标开始填。初始化的时候也是从1号下标开始初始化。当然如果你开n个空间也可以。

状态转移方程:

根据我们上面的分析我们可以知道,从第四个台阶开始,方法数就是前面三个台阶方法数的和。因此.dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]

初始化:

因为要用到前3个位置的状态,因此我们需要将dp表1、2、3下标的位置初始化,初始化成1,2,4即可。这是从上面分析得来的。

填表顺序:

这道题和泰波那契那道题一样,要从左往右填写。

返回值:

要求第n个台阶的方法数,因此返回dp[n]即可。这里开的空间是n+1。

接下来就是编写代码,这道题恶心就恶心在它的数据上。你写一下你就知道了。

面试题 08.01. 三步问题 - 力扣(LeetCode)

三、代码编写

这里要注意的地方就是你的数据是有可能超出存储范围的,因此你需要对它取模,而且有可能是两个数相加的和超出了范围,这是这道题恶心的地方。

class Solution 
{
    const int mod = 1e9 + 7;
public:
    int waysToStep(int n) 
    {
        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];
     }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值