1. 题目描述
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
示例 1:
输入:2输出:1解释:F(2) = F(1) + F(0) = 1 + 0 = 1.
示例 2:
输入:3输出:2解释:F(3) = F(2) + F(1) = 1 + 1 = 2.
示例 3:
输入:4输出:3解释:F(4) = F(3) + F(2) = 2 + 1 = 3.
2. 解题思路
(1)暴力递归:最简单的方式就是递归,根据题目中给出的斐波那契数列公式进行递归遍历。这种方式存在重复调用计算的问题。
- 时间复杂度:O(n**2**)
- 空间复杂度:O(1)
(2)递归 + 缓存:由于递归在遍历的过程中,存在很多节点重复计算的情况,所以我们可以将每次求的值进行缓存,以便于后面计算时使用。这里我们使用闭包来缓存每次计算的值。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
(3)动态规划:这里使用了动态规划,本质上也是在对已经计算好的结果进行缓存,只不过不用递归了,而是显式的进行迭代。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
(4)动态规划:这里使用了动态规划,我们发现每次计算fib(N),只需要用到fib(N-1)和fib(N-2),所以只需要使用两个变量来缓存就好了。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
3. 代码实现
(1)暴力递归
(2)递归 + 缓存/*** @param {number} N* @return {number}*/var fib = function(N) {if (N < 1) return 0if (N === 1 || N === 2) return 1;return fib(N - 1) + fib(N - 2);};
(3)动态规划var fib = (function(N) {if (N === 1 || N === 2) return 1;let arr = [0,1,1]return N => {if(N<arr.length){return arr[N]}for(let i = arr.length; i <= N; i++){arr[i] = arr[i-1] + arr[i-2]}return arr[N]}})();
(4)动态规划/*** @param {number} N* @return {number}*/var fib = function(N) {if (N < 1) return 0if (N === 1 || N === 2) return 1;let pre = 1, cur = 1, sum = 0; // pre前一位数字的累加和, cur当前数字, sum当前数字的累加和for (let i = 3; i <= N; i++) {sum = pre + cur;pre = cur;cur = sum;}return cur;};
/*** @param {number} N* @return {number}*/var fib = function(N) {if (N < 1) return 0if (N === 1 || N === 2) return 1;const res = [0,1]for(let i= 2; i <= N; i++){res[i] = res[i-1] + res[i-2]}return res[N]};
4. 提交结果
(1)暴力递归
(2)递归 + 缓存
(3)动态规划
(4)动态规划
