青铜三人行之青蛙跳台阶

先说一个消息,为了方便互相交流学习,青铜三人行建了个微信群,感兴趣的伙伴可以扫码加下面的小助手抱你入群哦!
青铜三人行小助手

青蛙跳台阶问题

青铜三人行——每周一题@青蛙跳台阶

青蛙跳台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:2

示例 2:

输入:n = 7
输出:21

提示:

0 <= n <= 100

解题思路

这次的题看起来偏实际一些,读起来会有点绕。实际上书香在解题的时候,第一反应也是从正面开始考虑了上周讨论的贪心算法 —— 考虑每多上一步时最多可能有几种上法,但发现穷举的数量还挺复杂的,并没有完成出代码(如果有完成的小伙伴可以来讨论下)…

既然这道题的难度是「简单」,应该不至于这么复杂吧。于是又从头考虑了下:

  • 如果台阶是1个,那么就只有一种上法
  • 如果台阶是2个,那么就有两种上法 —— 一次1步或一次2步

那么接着添加一个台阶,如果是3个呢?

  • 如果最后剩1个台阶,那么前面就要上2个台阶:前面的台阶有两种上法。
  • 如果最后剩2个台阶,那么前面就要上1个台阶:前面的台阶只有一种上法。

那么3个台阶的上法就是2个台阶的上法 + 1个台阶的上法 = 3种。

那么4个台阶呢?最后一步也只有2种情况:

  • 如果最后剩1个台阶,那么前面就要上3个台阶
  • 如果最后剩2个台阶,那么前面就要上2个台阶

于是4个台阶的上法就是3个台阶的上法 + 2个台阶的上法 = 5种

以此类推下去,我们会发现,n-1 个台阶的上法 + n -2 个台阶的上法 = n 个台阶的上法 。换成公式就是 f(n) = f(n-1) + f(n-2) 。
在这里插入图片描述
桥豆麻袋!好眼熟啊,我们似乎发现了事实的真相 ???这不就是一个典型的斐波那契数列吗???小样,换了身马甲,差点没认出你来!
在这里插入图片描述

代码

Talk is cheap, show me the code.

既然有了思路,这道题就很简单了。书香很快就给出了代码:

/**
 * @param {number} n
 * @return {number}
 */
var numWays = function(n) {
    if(n <= 1) return 1;
    else if(n === 2) return 2;  //台阶少的特殊情况

    let prev1 = 1; 
    let prev2 = 2;
    let current = 0;
    let mod = 1e9 + 7;
    for(let i = 3; i <= n; i++) {   //从3个台阶开始的通用情况
        current = (prev1 + prev2) % mod;
        prev1 = prev2;
        prev2 = current;
    }
    return current;
};

注意题目中,要求得到的答案要对 1e9 + 7 来求模,所以每次获取 current 变量的时候,都执行了 % 求模操作。

而 Helen 也给出了同样思路的递归解法:

var numWays = function(n) {
    const cache = {};
    function play (_n) {
        if (_n <= 1) {
            return 1;
        }

        if (cache[_n]) {
            return cache[_n];
        } else {
            cache[_n] = (play(_n - 1) + play(_n - 2)) % 1000000007;
            return cache[_n];
        }
    }
    return play(n); 
};

还记得递归和循环之间是可以相互转换的吗?

Extra go
这种小问题当然难不倒老曾,他在后悔给我们选了一道如此简单的题(开心的书香和 helen)。于是他随手写出了 go 语言的代码:

func numWays(n int) int {
    if n==0{
        return 1
    }

    if n==2 || n==1{
        return n
    }

    a := 1
    b := 2
    c := 0
    for i:=3;i<=n;i++{

       c = (a+b)%1000000007
       a = b 
       b = c 

    }
    return c
}

动态规划

OK,题目虽然简单,但是青铜三人行在复盘的时候,还是发现这种解法其实有个看起来挺高大上的名字:动态规划(英语:Dynamic programming,简称DP)。

虽然名字看起来很高大上,其实背后的思想很简单:若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。

比如这道题,我们把上台阶的问题分解成了每增加一个台阶时,应该有几种情况的子问题,从而发现了在每增加一个台阶时,跟之前情况之间的关系,找出了其中共通的模式,来解决题目。

这种思考问题的方式,往往在数学、管理科学、计算机科学、经济学和生物信息学中,解决前后关联比较复杂的问题时,会非常的有用。

下周见~


三人行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值