剑指offer | 面试题10:斐波那切数列

转载本文章请标明作者和出处
本文出自《Darwin的程序空间》
本文题目和部分解题思路来源自《剑指offer》第二版

在这里插入图片描述

开始行动,你已经成功一半了,献给正在奋斗的我们

题目

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

F(0) = 0;F(1) = 1;F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。

解题分析与代码

这道题可能大学学过计算机的首先都会想到递归算法,求第n个数,那么就可以递归去求n-1和n-2那么就知道了n的答案,具体代码如下。

  • 方式1 | 递归解法(不可取)
public class Offer10_Fib {

    public static void main(String[] args) {
        System.out.println(fib(6));
    }

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

这种方式的好处就是代码比较简洁,明了,但是效率并不高,因为重复计算了太多的值,如果要计算n=5的值,那么我们的调用数如下:
在这里插入图片描述

(图片来源于网络)

我们可以看到即使n=5,n=1都被计算了5次,那么想想看如果n=100,那么这个算法会有多慢。所以在面试的过程中,这种方式捎带提过就好,不能作为给面试官的标准输出答案。
  • 方式2 | 动态规划(通用,一般是面试官想看到的解法)
那些遗忘过去的人注定要重蹈覆辙 ~ 动态规划
所谓动态规划: 现在通过分析这个问题,我们可以将新的输入(或者不在数据结构中的输入)与其对应的输出存储下来。或者在字典中查找输入并返回相应的输出结果。这样当你在进行一些计算时,你可以检查数据结构中是否存在该输入,如果数据输入存在的话就可以直接获得结果。我们将与这种方法相关的技巧称作动态规划。--来源于百度

就是我们已经计算出来的值,就要利用到,不再去计算第二遍;

你品,你细品,你仔细品,是不是在点方法1是个**,,咳咳~~~

我们首先定义长度为2的一个数组arr,来记录F(n)的值,首先arr[0]对应的是0(F(0) = 0)、arr[1]对应的是1(F(1) = 1);
然后当要计算n=2的时候,我们把arr[1]复制到arr[0]的位置,然后arr[1]等于原来的arr[1]+arr[0],这就相当于我们保存了n=1和n=2的值,如果我们所求为n=5,那么我们就重复以上操作,指导arr[1]记录的是n=5的值即可。

这种解法只需要遍历一遍即可,时间复杂度为O(n),空间复杂度为O(1),因为我们只定义了常数个变量。

public class Offer10_Fib {

    public static void main(String[] args) {
        System.out.println(fib(6));
    }

    public static int fib(int n) {
        int[] arr = new int[2];
        arr[1] = 1;
        if (n < 2) {
            return arr[n];
        }

        int temp;
        for (int i = 2; i <= n; i++) {
            temp = arr[1];
            arr[1] = arr[0] + arr[1];
            arr[0] = temp;
        }
        return arr[1];
    }
}
  • 方式3 | 线性代数(可以向面试官展示自己的知识面,不通用)

这个解法需要一点线性代数的基础,碰巧笔者大学线性代数考了96,(我同桌抄我的考了95…),于是看到何海涛(剑指offer作者)提出这种解法的时候,下床三下五除二就实现了,但是面试官一般不是真的考你这种算法,毕竟我们不是学数学的,所以知道的能用上就装个*,不知道的了解一下即可。
在这里插入图片描述

class Solution {
    public int fib(int n) {

        if (n == 0) return 0;
        if (n == 1) return 1;

        int[][] matrix1 = new int[][]{new int[]{0, 1}, new int[]{0, 0}};
        int[][] matrix2 = new int[][]{new int[]{0, 1}, new int[]{1, 1}};

        for (int i = 1; i < n; i++) {
            matrix1 = matrixMultiplication(matrix1, matrix2);
        }

        return matrix1[0][1];
    }

    /* 矩阵相乘计算 */
    private int[][] matrixMultiplication(int[][] matrix1, int[][] matrix2) {

        if (matrix1.length != matrix2[0].length) {
            return null;
        }

        int[][] result = new int[matrix1.length][matrix2[0].length];

        for (int i = 0; i < matrix1.length; i++) {
            for (int j = 0; j < matrix2[0].length; j++) {
                for (int k = 0; k < matrix2.length; k++) {
                    result[i][j] += matrix1[i][k] * matrix2[k][j];
                }
            }
        }

        return result;
    }
}

拓展

和本题高度类似的有爬楼梯问题,leetcode上搜索爬楼梯即可,我这里给出我的答案,请同学们参考。

class Solution {
    public int climbStairs(int n) {
        if (n <= 0) {
            return 0;
        } else if (n == 1) {
            return 1;
        } else if (n == 2) {
            return 2;
        }

        int[] result = new int[2];
        result[0] = 1;
        result[1] = 2;

        for (int i = 2; i < n; i++) {
            int temp = result[1];
            result[1] = result[0] + result[1];
            result[0] = temp;
        }

        return result[1];
    }
}
喜欢的朋友可以加我的个人微信,我们一起进步
发布了156 篇原创文章 · 获赞 19 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_36929361/article/details/104333919