509. 斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fibonacci-number
一眼望去非常简单,递归几行解决问题
class Solution {
public int fib(int N) {
if(N==0){
return 0;
}else if(N==1){
return 1;
}else{
return fib(N-1)+fib(N-2);
}
}
}
问题在于,由于此问题中,递归是Q(n)递归为计算Q(n-1)和Q(n-2),这就导致了:
N= | 调用次数 |
---|---|
n | 1 |
n-1 | 1 |
n-2 | 2 |
n-3 | 3 |
n-4 | 5 |
n-5 | 8 |
n-6 | 13 |
可以看出,随着N和n的距离增加,函数的调用次数是增加的,而调用次数正好也是一个斐波那契数列(n-i会被n-i+1和n-i+2调用)
到了n-19,已经要被调用6000多次!
那么,我们把之前的运算结果都存起来,不就可以避免重复调用了吗!(牺牲一定堆内存换取效率(似乎也节省了栈内存))
class Solution {
public int fib(int N) {
//用来存fib(n)
int re[] =new int[N+1];
if(N==0){
return 0;
}
re[1]=1;
for(int i=2;i<N+1;i++){
re[i]=re[i-1]+re[i-2];
}
return re[N];
}
}
能不能再节省一点?
计算只用到前两个结果
所以,可以! 只用三个int类型存中间结果就行了!
class Solution {
public int fib(int N) {
int small=0;
int big=1;
int temp;
for(int i=0;i<N;i++){
temp=small+big;
small=big;
big=temp;
}
return small;
}
}
还有更简单的
康康这个:
斐波那契数列通项公式推导
还有什么事是数学解决不了的吗?
class Solution {
public int fib(int N) {
return (int)Math.round(Math.pow((1 + Math.sqrt(5)) / 2, N)/ Math.sqrt(5));
}
}
然鹅,内存消耗还是感人
LeetCode中内存消耗最低的例程就是第三种解法,然鹅我拿去跑依旧5%