在学校的教材中学到的斐波那契数列的解法
将数值存储在数组的两个元素之间,并且不断循环赋值
class Solution {
public:
int fib(int n) {
int f[2] = {0, 1};
if( n == 0) return 0;
while(--n) {
f[n&1] = (f[0] + f[1]) % 1000000007;
cout<<f[1]<<endl;
}
return f[1];
}
};
当且仅当f[0]==f[1]的时候可以适用,写一篇博文记录一下
当f[0]==f[1]=1时
1.当输入n为奇数 eg n=5;
--n=4 n&1=0 f0=2 f1=1
--n=3 n&1=1 f0=2 f1=3
--n=2 n&1=0 f0=5 f1=3
--n=1 n&1=1 f0=5 f1=8
可见当 - - n为奇数时,f1将会储存正确解,所以此时输出正确
2.当输入n为偶数 eg.n=6
--n=5 n&1=1 f0=1 f1=2
--n=4 n&1=0 f0=3 f1=2
--n=3 n&1=1 f0=3 f1=5
--n=2 n&1=0 f0=8 f1=5
--n=1 n&1=1 f0=8 f1=13
可见当 - - n为偶数时,f1将会储存正确解,所以此时输出正确
而当f[0]=0 f[1]=1时
1.当输入n为奇数 eg n=5;
--n=4 n&1=0 f0=1 f1=1
--n=3 n&1=1 f0=1 f1=2
--n=2 n&1=0 f0=3 f1=2
--n=1 n&1=1 f0=3 f1=5
可见当 - - n为奇数时,f1将会储存正确解,所以此时输出正确
2.当输入n为偶数时 eg.n=6
--n=5 n&1=1 f0=0 f1=1
--n=4 n&1=0 f0=1 f1=1
--n=3 n&1=1 f0=1 f1=2
--n=2 n&1=0 f0=3 f1=2
--n=1 n&1=1 f0=3 f1=5
可以发现滞后了一步,是因为第一个f0+f1被f1吞了?
修改f[0]=1 f[1]=2
正确情况是 1 2 3 5 8 13…
1.当输入n为奇数 eg n=5;
--n=4 n&1=0 f0=3 f1=2 ---f0 = f[2] f1 = f[1]
--n=3 n&1=1 f0=3 f1=5 ---f0 = f[2] f1 = f[3]
--n=2 n&1=0 f0=8 f1=5 ---f0 = f[4] f1 = f[3]
--n=1 n&1=1 f0=8 f1=13 ---f1 = f[4] f1 = f[5]
是正确的
2.当输入n为偶数时 eg.n=6
--n=5 n&1=1 f0=1 f1=3
--n=4 n&1=0 f0=4 f1=3
--n=3 n&1=1 f0=4 f1=7
--n=2 n&1=0 f0=11 f1=7
--n=1 n&1=1 f0=11 f1=18
可见其实逻辑是错误的
漏洞其实是非常明显的:
而当n为奇数时:第一个- -n 将会把f0+f1(即f2)存入f0中,而后续f0=f0+f1实际上等于f2+f1,所以是正确的。
当n为偶数时:第一个- -n 将会把f0+f1(即f2)存入f1中,而后续f0=f0+f1实际上等于f0+f2,所以出现f0 != f1的情况下,这就是错误的。
书上的算法只针对传统的斐波那契数列,因为这个数列就是定义f0==f1=1;f[n] = f[n-1] + f[n-2];失去第一点也不可以
对在f0!=f1的情况下还是要使用这种做法进行分析:
- 首先必须保证逻辑正确,所以计算的步骤必须和n为奇数时一样----先存f0再存f1
- 其次返回结果时要找到正确解在f0还是f1-----对奇数情况进行分析,输入n一共会进行n-1步计算,且f1在偶数次循环时为正确解,于此同时f0存储的值为F[n-1] ,也就是我们需要的偶数解。
- 经过上诉分析,只要输入一个偶数n,使其++得到奇数,然后最后返回f[0]即可
- 所以得到改进代码
class Solution {
public:
int fib(int n) {
int f[2] = {1, 2};
int flag = 0;
if( n == 0) return 1;
if( n % 2 == 0) {
flag = 1;
n++;
}
while(--n) {
f[n&1] = (f[0] + f[1]) % 1000000007;
cout<<f[1]<<endl;
}
return flag? f[0]:f[1];
}
};
时间复杂度O(n),空间复杂度O(1)