剑指offer.10.斐波拉契数列之数学递归公式的巧妙变形

前言

第一次看到用数学公式去简化,感觉数学真的是理工科的基础,理工科的根。
通过矩阵递推公式来简化算法,把斐波拉契数列的时间复杂度降到了O(log2N)。

一、从数学出发

1、思想

在这里插入图片描述
这是leetcode官方解答的原图。

可以看到这个题就是初等矩阵的变换,左乘初等矩阵执行相应的行变换,即把第二行加到第二行,然后再交换两行。这也是题目想要的变换。不断的进行这种变换,就意味着左边不断乘上这样的初等矩阵E。
所以想得到F(N+1)和F(N)就乘En
转化成数学问题,再进行数学的化简,瞬间高级了起来。这种思想值得学习。

2、源码

//设置取模的大小MOD和初等矩阵E
    static final long MOD = 1000000007;
    static final int[][] E = {{1,1},{1,0}};
    public int fib2(int n) {
        if(n==0 || n==1)
            return n;
        //执行E的n-1次方得到F(N)和F(N-1)
        //这里只需要看[0][0]位,毕竟F(1) == 1,F(0)==0,相加只用得到resultE[0][0] * 1 + 0 * resultE[0][1];
        return pow(n-1)[0][0];
    }
    public int[][] pow(int n){
        int[][] resultM = {{1,0},{0,1}};
        int[][] tempM = E;
        while(n > 0){
            //等于1就把前面准备好的矩阵乘上,即指数加上。否则对resultM矩阵不做任何操作,毕竟该位为0
            if((n & 1) == 1){
                resultM = multiply(resultM,tempM);
            }
            //计算下一位等于1时的矩阵值。左边一位是0是1都把它乘上,为更左边的1做准备。
            tempM = multiply(tempM,tempM);
            //右移一位,推动循环
            n >>= 1;
        }
        return resultM;
    }
    public int[][] multiply(int[][] M1,int[][] M2){
        int[][] R = new int[2][2];
        for(int i = 0;i < 2;i++){
            for(int j = 0;j<2;j++){
                R[i][j] = (int)((long)(M1[i][0] * M1[0][j]) + (long) (M2[i][1] * M2[1][j]) % MOD);
            }
        }
        return R;
    }

二、普通做法

普通做法实在是太简单了,有递归,虽代码简洁,但是会有很多多余的计算,很耗费时间;有非递归,根据递推公式一步一步的走,时间复杂度为O(N)。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值