【问题】一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
时间限制:1秒 空间限制:32768K
思路1:递归法
利用二叉树,结点为当前剩余台阶数,左孩子为跳 1 级,右孩子为跳 2 级,直到剩余台阶数为 0 即叶子结点时,累加跳法数量。
算法很简单,以下为 JavaScript 实现代码(运行超时):
var ways = 0;
// 树结点
// function TreeNode(val) {
// this.val = val;
// this.left = null;
// this.right = null;
// }
// 创建二叉树,无须创建节点,只是利用了二叉树的思想
function createTree(number) {
// var T = new TreeNode(number);
if (number >= 1)
// T.left = createTree(number - 1);
createTree(number - 1);
if (number >= 2)
// T.right = createTree(number - 2);
createTree(number - 2);
if (number == 0) {
ways++;
}
// return T;
}
// main
function jumpFloor(number)
{
ways = 0;
createTree(number);
return ways;
}
优点:易于理解,与自己画图的思路一样。
缺点:即使没有真的创建二叉树出来,当 number 比大的时候,由于递归,空间时间复杂度还是比较高,程序效率也比较低。
思路2:递归转迭代(斐波那契数列)
将思路1的递归改成迭代写法,会发现很像斐波那契数列。根据实验结果,分别求出 number 从 0 到 10 的结果为:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89],也确实很符合斐波那契数列规律。下面我们利用数学归纳法验证一下:
记 Fb(i) 为斐波那契数列第 i 项的值(i 从 0 开始),jump(i) 为台阶数为 i 时的总跳数,number 为台阶数
1. 当 number = 0 或 1 的时候,跳法为 1,jump(0) = Fb(0),jump(1) = Fb(1) 成立;
2. 假设当 number = n (n > 1) 的时候,有 jump(n) = Fb(n) 成立,则当 number = n + 1 的时候, 有两种互斥的跳法:
① 跳到第 n 级,再跳 1 级,则跳到第 n 级有几种方法,此种跳法就有多少,即为 jump(n)。
注意这里并不是 jump(n) + 1,这里是指跳法为“跳到第 n 级,再跳 1 级”这种跳法,“再跳1级”指基于跳 n 级的基础上
② 跳到第 n - 1 级,再跳 2 级,跳法为 jump(n-1)。
注意这里只能一口气跳 2 级了,否则跳 1 级,就和跳法①重叠了
即有jump(n+1) = jump(n) + jump(n-1) = Fb(n) + Fb(n-1) = Fb(n+1)
jump(n+1) = Fb(n+1) 成立。
所以,本题目等同于求斐波那契数列的第 number 项。代码如下(通过):
function jumpFloor(number)
{
var fb = [1, 1];
for (var i = 2; i <= number; i++) {
fb.push(fb[i - 2] + fb[i - 1]);
}
return fb[number];
}
优点:速度快
缺点:空间换时间,需要存储前面的计算结果(可以通过3个变量重复利用,来降低空间)