一、题目描述
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 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
二、题目解析
-
递归法
如果没有时间上的限制,斐波那契的一般解决方法是递归的方法。
/** * @param {number} n * @return {number} */ var fib = function(n) { if(n < 2) return n; return fib(n-1) + fib(n-2); };
但是这种方法会有大量重复的计算,导致超出leetcode的时间限制
-
记忆递归法
上面说到,未经优化的递归法会进行大量重复的计算,以fibonacci(5)为例
fibonacci(5) = fibonacci(4) + fibonacci(3); fibonacci(4) = fibonacci(3) + fibonacci(2);
可以看到,重复计算了fibonacci(3)两次。
为了减少这种重复计算,我们可以将计算过的结果保存起来,确保不会进行重复的计算。
/** * @param {number} n * @return {number} */ var fib = function(n) { const memo = [0,1]; const fibonacci = function(n) { if(memo[n] != null) { return memo[n] % 1000000007; } return memo[n] = (fibonacci(n-1) + fibonacci(n-2)) % 1000000007; } return fibonacci(n); };
-
动态规划法
从计算效率、空间复杂度上看,动态规划是本题的最佳解法。
动态规划解析
- 状态定义: 设dp为以为数组,其中dp[i]的值代表斐波那契数列第i个数字
- 转移方程: dp[i] = dp[i-1] + dp[i-2],即对应数列定义f(n) = f(n-1) + f(n-2)
- 初始状态: dp[0] = 0,dp[1] = 1,即初始化前两个数字
- 返回值: dp[n],即斐波那契数列的第n个数字
/** * @param {number} n * @return {number} */ var fib = function(n) { const dp = [0,1]; for(let i = 2;i <= n;i ++) { dp[i] = (dp[i-1] + dp[i-2]) % 1000000007; } return dp[n]; };
- 时间复杂度: O(n)
- 空间复杂度: O(n)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof