每日一题——[剑指 Offer 10- I. 斐波那契数列]

148 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1

F(N) = F(N - 1) + F(N - 2), 其中 N > 1

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

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

示例 1:

输入:n = 2 输出:1

示例 2:

输入:n = 5 输出:5

提示:

0 <= n <= 100

思路分析:

这题作为力扣的基础题,主要考查了动态规划和记忆化搜索的思想,这里我们主要使用动态规划的方法进行解决。

我们先了解斐波那契数列的组成,前两个数字等于自己本省,然后由前两个数字组成第三个数字,以此类推直到推导出n的结果。

方法一:

由斐波那契数列的定义我们可以很容易推导出它的公式即:b[n]=b[n - 1] + b[n - 2];

这种暴力做法是可以得出结果的,但往往会因为超时而不能成功AC题目。所以我们要对其公式进行优化,把时间

的复杂度为O(2^n),即2的n次方。

class Solution {
public:
    int fib(int n) {
​
        if(n == 0) return 0;
        if(n == 1) return 1;
        return fib(n - 1) + fib(n - 2); 
​
    }
};
​

注意:这种暴力方法时间复杂度过高,往往会出现超过时间限制的情况。

方法二:

对原有的算法进行优化,使用根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n)的实现。由于 F(n)只和 F(n-1)与 F(n-2)有关,因此可以使用滚动数组把空间复杂度优化成 O(1)。一下代码将使用这种方式编写

class Solution {
public:
    int fib(int n) {
​
      if(n < 2) return n;
      const int N = 1000000007;
      int r = 1, p = 0, q = 0;
      // 滚动数组
      for(int i = 2;i <= n;i ++)
      {
        p = q;
        q = r;
        r= (p + q) % N;
      }
      return r;
​
    }
};

总结:对于动态规划的问题,我们可以先用暴力思想得出一般解,再想方法对其进行优化。