先说一个消息,为了方便互相交流学习,青铜三人行建了个微信群,感兴趣的伙伴可以扫码加下面的小助手抱你入群哦!
青蛙跳台阶问题
青铜三人行——每周一题@青蛙跳台阶
青蛙跳台阶问题
一只青蛙一次可以跳上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)。
虽然名字看起来很高大上,其实背后的思想很简单:若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。
比如这道题,我们把上台阶的问题分解成了每增加一个台阶时,应该有几种情况的子问题,从而发现了在每增加一个台阶时,跟之前情况之间的关系,找出了其中共通的模式,来解决题目。
这种思考问题的方式,往往在数学、管理科学、计算机科学、经济学和生物信息学中,解决前后关联比较复杂的问题时,会非常的有用。
下周见~
三人行