第七题 斐波那契数列
题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。(n<=39)
斐波那契数列:1,1,2,3,5…【 fn = f(n-1) + f(n-2) 】
开始我用递归去做:
function Fibonacci(n)
{
// write code here
if (n < 0 || n > 39 || typeof(n) != 'number'){
return false;
}
else if (n === 0){
return 0;
}
else if (n === 1){
return 1;
}
else return Fibonacci(n-1) + Fibonacci(n-2);
}
当数字比较大时,需要很多重复计算,运行时间太长,不通过。比如我们原本计算5时,要算4+3→(3+2)+(2+1)→(2+1)+(1+0)+(1+0),也就是说 f(n-2) 要被分别重复计算。
在答案中学习了一个递归改进:
function Fibonacci(n)
{
return typeof cache[n] === 'number'
? cache[n]
: cache[n] = Fibonacci(n - 1) + Fibonacci(n - 2);
}
var cache = {
0: 0,
1: 1
};
在递归法的基础上,新建一个对象,用于在递归时存储 f(0) 至 f(n) 的值,改进后的递归某项只要被计算过,之后就可以直接从cache中取了。缺点是需要使用 O(N)的额外空间。
改用迭代(动态规划思想):
function Fibonacci(n)
{
// write code here
var fibonacci = [0,1];
if (n < 0 || n > 39 || typeof(n) != 'number') {
return false;
}
for (var i = 2; i <=n; i++){
fibonacci[i] = fibonacci[i-1] + fibonacci[i-2];
}
return fibonacci[n];
}
运行时间:13ms,占用内存:5432k
不用数组来存每项的值:
function Fibonacci(n)
{
// write code here
var f0 = 0, f1 = 1, f2;
if (n < 0 || n > 39 || typeof(n) != 'number') {
return false;
}
for (var i = 2; i <=n; i++){
f2 = f0 + f1;
f0 = f1;
f1 = f2;
}
return fibonacci[n];
}
这样空间复杂度降为 O(1)
第八题 青蛙跳台阶
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
分析:
设跳上 n 级台阶有 f(n) 种跳法。在所有跳法中,青蛙的最后一步只有两种情况: 跳上 1 级或 2 级台阶。
- 当为 1 级台阶: 剩 n-1个台阶,此情况共有 f(n-1) 种跳法;
- 当为 2 级台阶: 剩 n-2个台阶,此情况共有 f(n-2) 种跳法。
f(n) 为以上两种情况之和,即 f(n)=f(n-1)+f(n-2) ,以上递推性质为斐波那契数列。本题可转化为求斐波那契数列第 n 项的值。
第九题 变态跳台阶
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析:
设跳上 n 级台阶有 f(n) 种跳法:
- 当 n = 1:只有 f(1) = 1 种跳法;
- 当 n = 2:有 f(2) = f(1) + f(0) = 2 种跳法;
- 当 n = 3:第一步跳 1 级,还剩 2 级有 f(2) = 2 种跳法;第一步跳 2 级,还剩 1 级,有 f(1) = 1 种跳法;第一步跳 3 级,f(0) = 1 种跳法。即:f(3) = f(2) + f(1) + f(0);
也就是说:
- f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(1) + f(0);
- f(n-1) = f(n-2) + f(n-3) + f(n-4) + … + f(1) + f(0);
两项相减,得 f(n) - f(n-1) = f(n-1);
即 当 n =1, f(n) = 1; 当 n > 1, f(n) = 2f(n-1)
可以递归,或者用一个循环执行i * 2 (i 初始值为1),或者返回一个 2^(n-1) and so on
第十题 矩形覆盖
题目描述
我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
分析
- 当 n = 1 :大矩形为 2*1 ,显然只需要 1 种方法;
- 当 n = 2 :大矩形为 2*2 ,将两个长方形一起横着或竖着,有 2 种方法;
- 当 n = 3 :大矩形为 2*3 ,三块小矩形竖着 ;第一块小矩形竖着,第二块小矩形横着,那么第三块小矩形只能横着了;第一块小矩形横着,那么剩下的两块小矩形也只能一块竖着一块横着,有 3 种方法;
也就是说,当有一块矩形横着的时候,也要有一块矩形一起横着,我们可以把它们想成绑定在一起。那么就相当于,矩形只能选 2*1 或者 2*2 的。那…不就是青蛙跳台阶问题吗??于是又回到了斐波那契数列。太强了8