LeetCode——509.斐波那契数列

题目

斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

给定 N,计算 F(N)。

思路

利用一个递归调用,就可以做解答了。

代码

class Solution {
    public int fib(int N) {
        int result=0;
        if(N==0)
            result=0;
        if(N==1)
            result=1;
        if(N>=2)
            result=fib(N-1)+fib(N-2);
        return result;
    }
}

结果

只是利用了一次递归,这样子就会很慢。不好
在这里插入图片描述

改进一下

因为利用递归,有一些数值需要重复计算多次,比如N=20的时候,F(19),和F(18)都会计算到F(17),所以重复计算,时间花销很大,我们利用一个数组来存放。

改进代码

class Solution {
    public int fib(int N) {
        if (N==0)
            return 0;
        else if (N==1)
            return 1;
        else 
        {
        int result[]=new int[N+1];
        result[0]=0;
        result[1]=1;
        for (int i=2;i<=N;++i)
            result[i]=result[i-1]+result[i-2];
        return result[N];
        }
    }
}

结果

经过这样一改进,就变得速度快很多了,但是这个东西,还可以有更加高效的
在这里插入图片描述

再改进思路

我们注意到,其实每一个数据都只是跟他前两个数据有关系,即后面的计算跟前面的数据是没有关系的,所以我们可以不必使用这个数组,改为三个整形变量来存储结果即可。

再改进代码

class Solution {
    public int fib(int N) {
        if (N<=1)
            return N;
        else
        {
            int first=0;
            int second=1;
            int result=1;
            for (int i=2;i<N;++i)
            {
                first=second;
                second=result;
                result=first+second;
            }
            return result;
        }
    }
}

结果

在这里插入图片描述
跟数组差不多,应该是开一个固定数组的花销也不是很大。

再再改进思路

利用矩阵快速幂来解决,这个算是非常妙的一种方法了【要有线性代数的基础】
F(N)=F(N-1)+F(N-2);变为F(N)=F(N-1)*1+F(N-2)*1;这样,我们利用一个基础的矩阵
[[1,1],[1,0]]就可以实现上面的情况了。最后,我们只需要返回结果矩阵的[0][0]位置的数值即可。
在这里插入图片描述

再再改进代码

class Solution {
    public int fib(int N) {
        if (N<=1)
            return N;
        //基础矩阵
        int base[][]={
                    {1,1},
                    {1,0}
                    };

        //结果矩阵
        int result[][]={
                {1,1},
                {1,0}
        };

		//本来就是要基础矩阵连乘N-1次,然后现在,因为结果矩阵的左上角已经是F(2)的结果,已经给出来了,所以,实际需要连乘 N-2次。
        for (int i=2;i<N;++i)
        {
            multiply(result,base);
        }
        return result[0][0];
    }

	//矩阵相乘
    public void multiply(int[][] A, int[][] B) {
        int x = A[0][0] * B[0][0] + A[0][1] * B[1][0];
        int y = A[0][0] * B[0][1] + A[0][1] * B[1][1];
        int z = A[1][0] * B[0][0] + A[1][1] * B[1][0];
        int w = A[1][0] * B[0][1] + A[1][1] * B[1][1];

        A[0][0] = x;
        A[0][1] = y;
        A[1][0] = z;
        A[1][1] = w;
    }

}

结果

在这里插入图片描述
这个就是利用矩阵来做得计算,这个就已经是很快了。

再再再改进思路

上面利用矩阵来计算,是一种很快的方法,但是,我们是每次都乘上一个矩阵,要乘N-1次,那么有什么办法可以加快这种乘法吗?有的,就是利用,矩阵快速幂
一个矩阵,连乘N-1次,N-1可以分解为多个 2的n次方相加,就是这个数,去转化为一个二进制数,当二进制数为1的时候,那个矩阵的2的n次方就需要进入到结果之中,我们就把结果与这个n次方相乘,这就可以减少我们做矩阵乘法的时间。

所以,我们可以利用这个思路,来消减我们做乘法的次数,这样子,更快!

再再再改进代码

class Solution {
    public int fib(int N) {
        if (N<=1)
            return N;
        //基础矩阵
        int base[][]={
                    {1,1},
                    {1,0}
                    };

        //结果数组
        int result[][]={
                {1,1},
                {0,0}
        };
        int test=N-2;//实际需要矩阵相乘的次数
        while(test>0)
        {
            if((test&1)==1) multiply(result,base);//矩阵的 2的n次方是否需要进入到结果中
            multiply(base,base);//计算矩阵的两次,四次,。。。。
            test>>=1;
        }
        return result[0][0];
    }

    //两个矩阵相乘
    public void multiply(int[][] A, int[][] B) {
        int x = A[0][0] * B[0][0] + A[0][1] * B[1][0];
        int y = A[0][0] * B[0][1] + A[0][1] * B[1][1];
        int z = A[1][0] * B[0][0] + A[1][1] * B[1][0];
        int w = A[1][0] * B[0][1] + A[1][1] * B[1][1];

        A[0][0] = x;
        A[0][1] = y;
        A[1][0] = z;
        A[1][1] = w;
    }

    //把矩阵B赋值给矩阵A
    public void voluation(int A[][],int B[][])
    {
        A[0][0]=B[0][0];
        A[0][1]=B[0][1];
        A[1][0]=B[1][0];
        A[1][1]=B[1][1];
    }

}

结果

这个就是算法的力量了,用到了一下矩阵快速幂,然后,速度又快,而且内存少,时间短。
在这里插入图片描述

题解利用数学公式

这个就真的想不到了,居然还能这样子做,只能给大佬喊666了!

题解数学代码

class Solution {
    public int fib(int N) {
        double goldenRatio = (1 + Math.sqrt(5)) / 2;
        return (int)Math.round(Math.pow(goldenRatio, N)/ Math.sqrt(5));
    }
}

结果

在这里插入图片描述
哈哈,虽然这种方法贼秀,但是还是比矩阵快速幂慢,真香!

总结

算法之路无穷尽也,只要多思考,多练习,收获还是会逐步增加的!跟大佬的差距真的不是一般的大,只能慢慢跟上了!

也是通过这个斐波那契数列,终于自己亲手实现了一此矩阵快速幂,使之变为我自己的东西,也顺带理解了快速幂。当年欠下的债,还是要自己亲手还回来!
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值