你真的会做斐波那契数列吗?

1,533 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

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

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

开始

以下用的是JavaScript

有多少同学写出来是下面这段代码的,老实给我站出来😂

    const fibonacci = function(n) {
        if (n < 2) {
            return n
        }
        return fibonacci(n - 1) + fibonacci(n - 2)
    }

这段代码存在两个问题,下面让我们来看看

我们把代码扔进力扣试一下,看看是否能提交成功

可以发现,力扣提示超出时间限制

image.png

其实代码本身没错,,我们可以用缓存来优化这段代码

先看一下优化前代码执行时间和优化后代码执行时间。

image.png

image.png

直接从20s => 0.13ms

解决超出时间限制

思路是这样的,创建一个Map,如果n已经记录,直接返回n对应缓存的值

    const map = new Map()
    const fibonacci = function(n) {
        if (n < 2) {
            return n
        }
        if (map.get(n)) {
            // 如果map有了,直接取出
            return map.get(n)
        }
        let result = fibonacci(n - 1) + fibonacci(n - 2)
        // 设置到map
        map.set(n, result)
        return result
    }

缓存这块是通用的,在很多地方都可以派上用场,可以提高性能

好!看我们把代码扔进力扣,看看这次是否能提交成功

image.png

可以看到,超出时间限制已经解决了,这次提示解答错误

excuse me??? 逻辑应该没问题呀,为什么要提示解答错误

我们看上面那张图,n为45的情况下,预期结果是134903163,但是我们的是:1134903170

我们看到题目里面,有这么一段话

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

为啥要模 1000000007呢?是因为

  1. 大数相加会超出数值范围
  2. 1000000007是一个质数(素数),对质数取余能最大程度避免冲突
  3. int64位的最大值为2^63-1,对于1000000007来说它的平方不会在int64中溢出

最终代码

    const map = new Map()
    const fibonacci = function(n) {
        if (n < 2) {
            return n
        }
        if (map.get(n)) {
            // 如果map有了,直接取出
            return map.get(n)
        }
        let result = fibonacci(n - 1) + fibonacci(n - 2)
        // 如果计算结果大于1000000007, 对其取模
        result >= 1000000007 && (result = result % 1000000007)
        // 设置到map
        map.set(n, result)
        return result
    }

可以看到在力扣中成功提交~~

image.png

结语

文章内容很low,不喜勿喷。有啥错误或评价可以评论区指出,主要是想让你们看到缓存的作用数值范围小知识,谢谢