剑指offer:斐波那契数列相关的三道题

前言

       如果我们需要重复多次计算相同的问题,通常可以选择递归和循环两种方法,递归的代码简洁,利用分治的算法思想,但是我们就要注意递归有时候效率会很低,而且容易栈溢出,接下来几题中,我们就要注意。

斐波那契数列相关的三道题

题目

  1. 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39。
  2. 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
  3. 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
  4. 我们可以用2 x 1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2 x 1的小矩形无重叠地覆盖一个2 x n 的大矩形,总共有多少种方法?

分析

       第一题如果用递归做,会发现效率很低,因为我们利用f(n)=f(n-1)+f(n-2)计算f(n),导致每次的重复计算f(n-1)、f(n-2),其实我们已经计算过这些值了,所以我们采用非递归来做。

       青蛙跳台阶的第一道,我们发现这就是斐波那契数列,跳到某一台阶的次数就是跳到前一格台阶的次数加上跳到前两格台阶的次数。采用和上一题一样的做法。

  青蛙跳台阶的第二道,我们用数学归纳法可以证明f(n)=2^2-1,其实这类题目也有很多,我们直接找到通式可以得到结果,像京东的几道题,还有求极限的,有兴趣可以去了解一下。

  方块覆盖问题,其实仔细想想,也是青蛙跳台阶一样的方法。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public int Fibonacci(int n) {
if(n<1)
return 0;
if(n==1)
return 1;
if(n==2)
return 1;
int a=1,b=1,reslut=0;
for(int i=3;i<=n;++i){
reslut=a+b;
a=b;
b=reslut;
}
return reslut;
}
public int JumpFloor(int target) {
if(target<=0){
return 0;
}
if(target==1){
return 1;
}
if(target==2){
return 2;
}
int a=1,b=2,c=0;
for(int i=3;i<=target;i++){
c=b+a;
a=b;
b=c;
}
return c;
}
public int JumpFloorII(int target) {
if(target<=0){
return 0;
}
else{
int c=1;
for(int i=1;i<target;i++){
c=2*c;
}
return c;
}
}
public int RectCover(int target) {
if(target<=0){
return 0;
}
if(target==1){
return 1;
}
if(target==2){
return 2;
}
int a=1,b=2,c=0;
for(int i=3;i<=target;i++){
c=b+a;
a=b;
b=c;
}
return c;
}