剑指 Offer 10- I 斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1

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

斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2

输出:1

示例 2:

输入:n = 5

输出:5

提示:

0 <= n <= 100

我能想到的就是递归...但是普通的递归太耗时了,画一棵递归树就知道了,有太多重复的计算

那么可以使用带备忘录的递归法,也就是把算完的值存在备忘录里,需要时拿出来,这种方法大大减小了计算量,可以通过。

突然想起来算法课上讲过....学的东西全还给老师了。记得老师讲这种方法是自顶向下

那么动态规划法就是自底向上的,从一个个小问题入手,最后解决整个大问题

动态规划

斐波那契的递推关系如下:

F(n)=F(n−1)+F(n−2)

那么可以用滚动数组法,可以节省空间

class Solution {
    public int fib(int n) {
        if(n<2)
            return n;
        int a=0,b=0,sum=1;
        for(int i=2;i<=n;i++){
            a=b;
            b=sum;
            sum=(a+b)%1000000007;
        }
        return sum;
    }
}

这一块儿就是要注意别忘了0和1的情况,以及循环算多少次,a,b,sum的初值各自是多少。

时间复杂度:O(n)

空间复杂度:O(1) 常数级

这个效率居然还挺高的

矩阵快速幂

这种方法可以降低时间复杂度

本来不想看这个方法,结果评论区大佬说字节面试要求写出这种方法。。。真就面试造火箭吗

思路如下:(我自己是绝对想不到这种方法的。。)

注意求F(n+1)时是M连乘n次,那么求F(n)时就应该连乘n-1次

什么是快速幂算法?

简单说就是增大底数以减小指数,从而减小循环运算的次数

class Solution {
    public int fib(int n) {
        if(n<2)
            return n;
        int[][] m={{1,1},{1,0}};
        int[][] temp=pow(m,n-1);
        return temp[0][0];
    }
    public int[][] multiply(int[][] a,int[][] b){
        int c[][]=new int[2][2];
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                c[i][j]=(int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % 1000000007);
            }
        }
        return c;
    }
    public int[][] pow(int[][] a,int n){
        //普通的幂算法,会超时的那种
        // for(int i=0;0<n;i++){
        //     m=multiply(m,m);
        // }

        //快速幂
        int[][] ret={{1,0},{0,1}};
        while(n>0){
            if((n&1)==1){
                ret=multiply(ret,a);
            }
            n>>=1;
            a=multiply(a,a);
        }
        return ret;
    }
}

才搞懂是个什么思路...

ret是个单位矩阵,用来存放最后的结果。n是幂指数。n&1也就是判断指数n是不是奇数,如果是的话就将a的值赋给它,调用multiply是因为没有将等号运算符重载,用单位矩阵乘一下就可以啦。然后n右移一位也就是指数减半,底数变为原来的2次方,经过logn次的计算就能算出最终结果了。

时间复杂度:O(log n)

空间复杂度:O(1)

参考:

1.斐波那契数列 - 斐波那契数列 - 力扣(LeetCode)

2.快速幂算法(全网最详细地带你从零开始一步一步优化)_刘扬俊的博客-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值