LeetCode | 面试题 08.01. 三步问题

相关标签

动态规划 DP、C 语言

题目描述

三步问题。有个小孩正在上楼梯,楼梯有 n 阶台阶,小孩一次可以上 1 阶、2 阶或 3 阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模 1000000007。

解题思路

这是一道基础动态规划题,根据 DP 的解题方法,我们将情况分为 n = 1, n = 2, n = 3 与 n > 3 四种情况讨论。

当 n 为 1 时,我们有且仅有最后一次上 1 阶楼梯这一种方法,f(1) = 1。

当 n 为 2 时,我们有最后一次上 1 阶楼梯和最后一次上 2 阶楼梯这两种方法,对应 f(2) = f(1) + 1 = 2。

当 n 为 3 时,我们有最后一次上 1 阶楼梯、最后一次上 2 阶楼梯和最后一次上 3 阶楼梯这两种方法,对应 f(3) = f(2) + f(1) + 1 = 4。

当 n 大于 3 时,小孩上到第 n 阶楼梯有 f(n) 种方法,按照最后一次抬腿上楼梯跨的阶数,可分为 “最后一次上 1 阶楼梯”、“最后一次上 2 阶楼梯” 和 “最后一次上 3 阶楼梯” 三种方法,对应的抬腿前已上台阶的方式数量为 f(n-1), f(n-2) 和 f(n-3),即 f(n) = f(n-1) + f(n-2) + f(n-3)。

按照以上思路写出代码如下:

int waysToStep(int n){
    if(n == 1){
        return 1;
    }
    else if(n == 2){
        return waysToStep(1) + 1;
    }
    else if(n == 3){
        return waysToStep(2) + waysToStep(1) + 1;
    }
    else{
        return (waysToStep(n - 1) + waysToStep(n - 2) + waysToStep(n - 3)) % 1000000007;
    }
}

执行后发现超时 😦

参考题解,对思路进行改进如下:
当 n = 4 时,f(4) = f(3) + f(2) + f(1)
当 n = 5 时,f(5) = f(4) + f(3) + f(2)
……
当 n = n 时,f(n) = f(n - 1) + f(n -2) + f(n - 3)

显然,对于每种阶数 n,上楼的方式仅取决于紧邻的前三种阶数的方式数量,且这三种方式的数量均出现在紧邻的前一种阶数的计算中,故设立一个四个元素大小的数组 kind 储存计算过程中的值,具体如下:

int waysToStep(int n){
    if(n < 3){
        return n;
    }
    if(n == 3){
        return 4;
    }
    //每增加一阶台阶,实现方法都是前三阶的方法数之和
    int *kind = (int*)malloc(sizeof(int) * 4);
    kind[0] = 1;
    kind[1] = 2;
    kind[2] = 4;
    for(int i = 3; i < n; ++i){
        kind[3] = (kind[0] + kind[1] + kind[2]) % 1000000007;
        for(int j = 0; j < 3; ++j){
            kind[j] = kind[j + 1];
        }
    }
    return kind[3];
}

执行后爆栈 😦

考虑到三个最大值可能为 1000000006 的数相加会超过 int 的范围,将 kind 数组的数据类型改为 long long,执行通过 😀

代码

int waysToStep(int n){
    if(n < 3){
        return n;
    }
    if(n == 3){
        return 4;
    }
    //每增加一阶台阶,实现方法都是前三阶的方法数之和
    long long *kind = (long long*)malloc(sizeof(long long) * 4);
    kind[0] = 1;
    kind[1] = 2;
    kind[2] = 4;
    for(int i = 3; i < n; ++i){
        kind[3] = (kind[0] + kind[1] + kind[2]) % 1000000007;
        for(int j = 0; j < 3; ++j){
            kind[j] = kind[j + 1];
        }
    }
    return kind[3];
}

请添加图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值