斐波那契数列-滚动数组算法探究

在学校的教材中学到的斐波那契数列的解法
将数值存储在数组的两个元素之间,并且不断循环赋值

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的情况下还是要使用这种做法进行分析:

  1. 首先必须保证逻辑正确,所以计算的步骤必须和n为奇数时一样----先存f0再存f1
  2. 其次返回结果时要找到正确解在f0还是f1-----对奇数情况进行分析,输入n一共会进行n-1步计算,且f1在偶数次循环时为正确解,于此同时f0存储的值为F[n-1] ,也就是我们需要的偶数解。
  3. 经过上诉分析,只要输入一个偶数n,使其++得到奇数,然后最后返回f[0]即可
  4. 所以得到改进代码
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)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值