《剑指offer》Java学习录:面试题9:斐波那契数列

面试题 9:斐波那契数列

题目:

写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列的定义如下:
f ( n ) = { 0 , n = 0 1 , n = 1 f ( n − 1 ) + f ( n − 2 ) , n > 1 f(n)= \begin{cases} 0, & \text{$n = 0$}\\ 1, & \text{$n = 1$}\\ f(n - 1) + f(n - 2),& \text{$n > 1$} \end{cases} f(n)=0,1,f(n1)+f(n2),n=0n=1n>1

分析

首先想到的是利用递归来解,如:

public static int fibonacci(int n) {
    if (n <=0 ) {
        return 0;
    } else if (n == 1) {
        return 1;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

该解法确实简单,很快就可以实现。让我们来分析一下:

我们以求解 f ( 10 ) f(10) f(10)为例分析求解过程。想要求 f ( 10 ) f(10) f(10)就的求 f ( 9 ) f(9) f(9) f ( 8 ) f(8) f(8),想要求 f ( 9 ) f(9) f(9)需要先求 f ( 8 ) f(8) f(8) f ( 7 ) f(7) f(7),同样想要求 f ( 8 ) f(8) f(8),又得先求 f ( 7 ) f(7) f(7) f ( 6 ) f(6) f(6) … 我们可以以树结构表达这种依赖关系。
在这里插入图片描述
不难发现,书中有很多节点重复,这意味着计算量会随着n的增大而急剧增大,事实上,用递归计算的时间复杂度是以n的指数递增的。我试了一下,当n为45时,就能很明显的发现获得结果需要等待一小会儿了。

改进

上面递归代码之所以慢是因为重复计算过多,当我们的递归从小往大计算时,第n次的结果总是前两次之后,而前两次刚好再前面两次已经计算过并记录了。

public static void main(String args[]) {
    System.out.println(fibonacci1(1000));
}

public static int fibonacci1(int n) {
    int[] result = {0, 1};
    if (n < 2) {
        return result[n];
    }
    int preNumberOne = 1;
    int preNumberTwo = 0;
    int number = 0;
    for (int i = 2; i <= n; i++) {
        number = preNumberOne + preNumberTwo;
        preNumberTwo = preNumberOne;
        preNumberOne = number;
    }
    return number;
}

斐波那契数列的运用:青蛙跳台阶

题目

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

分析

首先考虑最简单的情况,如果只有一级台阶,青蛙第一次跳的时候,显然只有一种跳法。如果有2级,有两种跳法:一种是跳一级、一种是跳两级。

再看一般情况,假如青蛙跳n级台阶总共有 F ( n ) F{(n)} F(n) 种跳法,当n > 2 时,第一次有两种不同的选择:1. 只跳1级,此时跳法数据等于后面剩下的n - 1级台阶的跳法数目,即 $ F(n - 1) 。 2. 只 跳 2 级 , 此 时 跳 法 数 目 等 于 后 面 剩 下 的 n − 2 级 台 阶 的 跳 法 数 目 , 即 。2. 只跳2级,此时跳法数目等于后面剩下的n - 2级台阶的跳法数目,即 2.2n2 F(n - 2)$ 。因此n级台阶的不同跳法总数为 F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n) = F(n - 1) + F(n - 2) F(n)=F(n1)+F(n2)。不难看出,这就是一个斐波那契数列。

斐波那契数列的运用:矩形覆盖

题目

我们可以用2 x 1的小矩形横着或者竖着去覆盖更大的矩形。请问用8个 2 x 1的小矩形无重叠地覆盖一个 2 x 8的大巨星,总共有多少种方法?矩形如图:

fugai
在这里插入图片描述

分析

先把2 x 8的覆盖方法次数记为 F ( 8 ) F(8) F(8) , 用1x2的矩形第一次覆盖到2x8上有两种方式:

  1. 竖着盖在最左边,此时的覆盖次数有 F ( 7 ) F(7) F(7)
  2. 横着覆盖最左上角, 此时覆盖次数记为 F ( 6 ) F(6) F(6)
  3. 所以,对于2x8的矩形区域, F ( 8 ) = F ( 7 ) + F ( 6 ) F(8) = F(7) + F(6) F(8)=F(7)+F(6)

显然,又是一个斐波那契数列。

结语

斐波那契数列相关题目特征:

  1. 每个步骤有两种不同的操作。
  2. 有0和1两个解。
  3. 经过两个不同操作后,问题规模将会得到不同程度的降低。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值