《剑指offer》第七至十题(js)

第七题 斐波那契数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值