【恋上数据结构与算法 第一季】斐波那契数列_位运算对2取模


持续学习&持续更新中…

学习态度:脚踏实地


已知斐波那契数列:0、1、1、2、3、5、8、13、21 …

方法一:递归实现

    public static int fib1(int n) {
        if(n <= 1) return n;
        return fib1(n - 2) + fib1(n - 1);
    }

方法一时间复杂度分析:

在这里插入图片描述

在这里插入图片描述

方法二:非递归实现(要求掌握)

	public static int fib2(int n) {
        if(n <= 1) return n;
        int first = 0;
        int second = 1;
        int sum;
        for (int i = 0; i < n - 1; i++) {
            sum = first + second;
            first = second;
            second = sum;
        }
        return second;
    }

上述两种方法的时间复杂度分析:

两种方法的时间复杂度分析

方法三:数学方程实现

方程实现

注意:并不是每种算法都会有方程式来解决该问题。

方法四:数组缓存实现(从n-0)

在这里插入图片描述

注意:上述分析的数列是从1 1 2 3 5 8 13 21... 开始的,没有0,下述代码是从0开始的。


    /*
        数组缓存实现
        斐波那契数列:0 1 1 2 3 5 8 13 21...
     */
    public static int fib3(int n) {
//        if (n == 0) return 0;
//        else if (n == 1 || n == 2) return 1;
//        else {
//            final int[] buff = new int[n + 1];
//            buff[0] = 0;
//            buff[1] = 1;
//            buff[2] = 1;
//            return fib3(buff, n);
//        }

        final int[] buff = new int[n + 3];
        buff[0] = 0;
        buff[1] = 1;
        buff[2] = 1;

        if (n <= 2) {
            if (n == 0) return 0;
            else if (n == 1 || n == 2) return 1;
            else return -1;
        }

        return fib3(buff, n);
    }

    private static int fib3(int[] buff, int n) {
        if (buff[n] == 0) {
            buff[n] = fib3(buff, n - 1) + fib3(buff, n - 2);
        }
        return buff[n];
    }

方法五:数组缓存实现(从0-n)


    /*
        fib3数组缓存是从n开始,然后到n-1,n-2,n-3......,显然会有重复调用
        可以考虑从0,1,2,3,4...... n实现
    */
    private static int fib4(int n) {
//        if (n == 0) return 0;
//        else if (n == 1 || n == 2) return 1;
//        else {
//            final int[] buff = new int[n + 1];
//            buff[0] = 0;
//            buff[1] = 1;
//            buff[2] = 1;
//
//            int current = 3;
//            while (current <= n) {
//                buff[current] = buff[current - 1] + buff[current - 2];
//                current++;
//            }
//            return buff[n];
//        }

        final int[] buff = new int[n + 3]; // 确保至少有3个容量大小
        buff[0] = 0;
        buff[1] = 1;
        buff[2] = 1;

        if (n >= 3) {
            int current = 3;
            while (current <= n) {
                buff[current] = buff[current - 1] + buff[current - 2];
                current++;
            }
        }

        return buff[n];

    }

注意:两种数组缓存方法中,方法五(从0-n)更好,因为没有进行递归操作,没有重复调用,都是直接相加。

方法六:滚动数组

在这里插入图片描述

    /*
        滚动数组来实现
    */
    private static int fib5(int n) {
        if (n <= 1) return n;
        final int[] buff = new int[2];
        buff[0] = 0;
        buff[1] = 1;
        for (int i = 1; i < n; i++) {
            final int temp = buff[0] + buff[1];
            if (buff[0] < buff[1]) {
                buff[0] = temp;
            } else {
                buff[1] = temp;
            }
        }
        return Math.max(buff[0], buff[1]);
    }

位运算对2取模

当n对2进行取模运算时,则根据n的二进制代码最低位就可以得到取模的结果:

  • 若n的二进制最低位为1,那么n肯定是奇数,那么n对2取模肯定为1
  • 若n的二进制最低位为0,那么n肯定是偶数,那么n对2取模肯定为0

那么如何取出n的最低位呢:

	final int a = 1; // 0b0001 & 0b0001  =  0b0001  =  1
	final int b = 2; // 0b0010 & 0b0001  =  0b0000  =  0
	final int c = 3; // 0b0011 & 0b0001  =  0b0001  =  1
	final int d = 4; // 0b0100 & 0b0001  =  0b0000  =  0

因此,n对2取模只需让n&1即可。

注意

  1. 使用int类型计算斐波那契数列,如果斐波那契数列项数是47(在本程序从0开始是46)的话,就会得到最大值:1836311903;因此,如果项数比较多,可以考虑使用更大的数据类型(例如longBigDecimal)来计算斐波那契数列。

  2. 乘、除、取模运算在编程语言中效率都很低,所以可以使用其它方式来进行优化代码。

参考

李明杰:开发用不到算法?那是因为你不会!.


本文完,感谢您的关注支持!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值