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;
}
};
总结:对于动态规划的问题,我们可以先用暴力思想得出一般解,再想方法对其进行优化。