面试题 9:斐波那契数列
题目:
写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列的定义如下:
分析
首先想到的是利用递归来解,如:
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);
}
}
该解法确实简单,很快就可以实现。让我们来分析一下:
我们以求解为例分析求解过程。想要求就的求和,想要求需要先求和,同样想要求,又得先求和 … 我们可以以树结构表达这种依赖关系。
不难发现,书中有很多节点重复,这意味着计算量会随着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级台阶总共有 种跳法,当n > 2 时,第一次有两种不同的选择:1. 只跳1级,此时跳法数据等于后面剩下的n - 1级台阶的跳法数目,即 $ F(n - 1) F(n - 2)$ 。因此n级台阶的不同跳法总数为。不难看出,这就是一个斐波那契数列。
斐波那契数列的运用:矩形覆盖
题目
我们可以用2 x 1的小矩形横着或者竖着去覆盖更大的矩形。请问用8个 2 x 1的小矩形无重叠地覆盖一个 2 x 8的大巨星,总共有多少种方法?矩形如图:
分析
先把2 x 8的覆盖方法次数记为 , 用1x2的矩形第一次覆盖到2x8上有两种方式:
- 竖着盖在最左边,此时的覆盖次数有。
- 横着覆盖最左上角, 此时覆盖次数记为。
- 所以,对于2x8的矩形区域,
显然,又是一个斐波那契数列。
结语
斐波那契数列相关题目特征:
- 每个步骤有两种不同的操作。
- 有0和1两个解。
- 经过两个不同操作后,问题规模将会得到不同程度的降低。