兔子数列问题——斐波那契优化

627 阅读2分钟

已知有一对兔子,每个月可以生一对兔子,而小兔子一个月后又可以生一对小兔子(比如:2月份出生的小兔子4月份可以生育)。也就是说,兔子的对数为:第一个月1对,第二个月2对,第三个月3对,第四个月5对.....假设兔子的生育期为两年,且不死。那么问题来了,你能说出每个月的兔子数么?

输入格式:

输入一个数n,表示第n个月,1<=n<=24。

输出格式:

输出这个月兔子的数目。

输入样例:

4

输出样例:

5

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

从pta和其他平台一直都有看见这个经典的问题,今天又刷到这一题,正好来总结一下。

基础版本

int fib(int x){
    if(x==1)
    return 1;
    if(x==2)
    return 2;
    return f(x-1)+f(x-2);
}

基础版本的缺点很明显,一时效率太慢,而是占内存占太大,一旦求大的月份就会爆栈。

image.png

迭代法

int fib(int x){
    if(x==1)
    return 1;
    if(x==2)
    return 2;
    itn a=1,b=2,i,sum=0;
    for(i=3;i<=x;i++){
        sum=a+b;
        a=b;
        b=sum;
    }
    return sum;
}

迭代法的好处就很明显了,用的是循环代替了递归,提高了空间和时间的利用。用a,b两个临时变量代替前一个数和前两个数,再加到sum中求总和,接着继续将三者不断替换,完成计算。

记忆化数组

define max 999999
int a[max];
int fib(int x){
    if(x==1)
    return 1;
    if(x==2)
    return 2;
    if(!a[x]){
        a[x]=f(x-1)+f(x-2);
        return a[x];
    }

}

记忆化数组解兔子数列的本质其实是dp,一直搞不明白的一点“简单dp==递推”这个概念一直不是很明白。但是记忆化数组就避免了递归次数过多导致的爆栈,但是吧,开的全局数组又会浪费空间。

作为一个仓鼠型程序员一直想优化一下记忆化数组,但是技术受限。以后学会了优化再更新这段代码。