剑指offer(9) 斐波那契数列第n项及其应用【JAVA】

目录

1.斐波那契数列第n项三种计算方法

2.应用一:青蛙跳台阶问题

3.应用二:小矩形放大矩形问题


注:本文部分内容来自剑指offer第二版

1.斐波那契数列第n项三种计算方法

递归:存在严重的性能问题,因为重复计算,时间复杂度O(2^n)

从下往上循环:解决了递归方法中重复计算的问题,时间复杂度O(n)

矩阵求解:利用乘方公式以及乘方性质,采用二分法求解,时间复杂度O(logn)

代码如下:(部分代码中结果用int,有溢出可能,所以采用long而不用int)

package example;

/**
 * 求斐波那契数列的第n项
 * 写一个函数,输入n,求斐波那契数列的第n项
 *
 * @author lvtong
 * @date 2020/2/1
 */
public class Example10 {
    public static void main(String[] args) {
        //方法1
        long start1 = System.currentTimeMillis();
        System.out.println("方法1:" + fibonacci1(10));
        long end1 = System.currentTimeMillis();
        System.out.println("耗时:" + (end1 - start1));
        //方法2
        long start2 = System.currentTimeMillis();
        System.out.println("方法2:" + fibonacci2(10));
        long end2 = System.currentTimeMillis();
        System.out.println("耗时:" + (end2 - start2));
        //方法3
        long start3 = System.currentTimeMillis();
        long[][] result = fibonacci3(10);
        System.out.println("方法3:" + result[0][1]);
        long end3 = System.currentTimeMillis();
        System.out.println("耗时:" + (end3 - start3));
    }

    /**
     * 最简单的办法,存在性能问题,因为大量的重复计算
     * 时间复杂度O(2^n)
     *
     * @param n n
     * @return 第n项
     */
    private static long fibonacci1(int n) {
        if (n <= 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        return fibonacci1(n - 1) + fibonacci1(n - 2);
    }

    /**
     * 从下往上计算
     * 时间复杂度O(n)
     *
     * @param n n
     * @return 第n项
     */
    private static long fibonacci2(int n) {
        int[] result = {0, 1};
        if (n < 2) {
            return result[n];
        }
        long first = 1;
        long two = 0;
        long number = 0;
        for (int i = 2; i <= n; ++i) {
            number = first + two;
            two = first;
            first = number;
        }
        return number;
    }


    // 关联矩阵
    private static final long[][] UNIT = {{1, 1}, {1, 0}};
    // 全0矩阵
    private static final long[][] ZERO = {{0, 0}, {0, 0}};

    /**
     * 求斐波那契数列
     *
     * @param n
     * @return
     */
    private static long[][] fibonacci3(int n) {
        if (n == 0) {
            return ZERO;
        }
        if (n == 1) {
            return UNIT;
        }
        // n是偶数
        if ((n & 1) == 0) {
            long[][] matrix = fibonacci3(n >> 1);
            return matrixMultiply(matrix, matrix);
        }
        // n是奇数
        long[][] matrix = fibonacci3((n - 1) >> 1);
        return matrixMultiply(matrixMultiply(matrix, matrix), UNIT);
    }

    /**
     * 矩阵相乘
     *
     * @param m r1*c1
     * @param n c1*c2
     * @return 新矩阵, r1*c2
     */
    private static long[][] matrixMultiply(long[][] m, long[][] n) {
        int rows = m.length;
        int cols = n[0].length;
        long[][] r = new long[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                r[i][j] = 0;
                for (int k = 0; k < m[i].length; k++) {
                    r[i][j] += m[i][k] * n[k][j];
                }
            }
        }
        return r;
    }
}

2.应用一:青蛙跳台阶问题

青蛙跳台阶问题
* 一个青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法。
* 分析:
* 1级台阶有1种跳法;2级台阶有两种跳法;
* 接着我们再来讨论一般情况。我们把”级台阶时的跳法看成n的函数,记为f(n)
* 当n>2时,第一次跳的时候就有两种不同的选择:
* 一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);
* 二是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)
* 因此,n级台阶的不同跳法的总数f(n)=f(n-1)+f(n-2).
* 分析到这里,我们不难看出这实际上就是斐波那契数列了。
* 如果青蛙一次也可以跳上n级,此时跳上一个n级台阶总共有f(n)=2^(n-1)种跳法。(可用数学归纳法证明)

3.应用二:小矩形放大矩形问题

剑指offer(9) 斐波那契数列第n项及其应用【JAVA】_第1张图片

你可能感兴趣的:(剑指offer)