一、题目
写一个函数,输入 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
二、题解
斐波那契数列算是比较经典的问题了,要做出来其实很简单,但是我们这里多思考一下,讨论一下现在常用的几个方法。
1.递归法:就是设置几个出口值,然后一直递归。(时间长,容易超出时间限制)
2.多一个记忆数组递归法:在递归的基础上,设置一个记忆数组,用来存储已经算出来的值,在递归时,如果遇到已有的值直接在记忆数组里面取(相比于方法一时间更快一些,可以省去一些重复计算的浪费)。
3.动态规划思想(讨论几种不同的逻辑写法): 1.用三个变量a,b,sum不断向前计算,循环n之后得到最后的值.2.用三个变量a,b,sum不断向前计算,循环n-1之后得到最后的值 3.全部放到dp数组中计算(这个最省时间)。
4.最后一定别忘记要%1000000007,细心!
三、代码(js)
//1.直接递归做 一般会超出时间限制
/**
* @param {number} n
* @return {number}
*/
let fib = function(n) {
if(n==0){
return 0;
}
if(n==1){
return 1;
}
return (fib(n-1)+fib(n-2))%1000000007;
};
// 2.用一个数组存储f(0)到f(n)的值 然后遇到已有的值直接在数组里面取
// 这种不会超出时间限制 但消耗的内存和用时很多
/**
* @param {number} n
* @return {number}
*/
//用new Array(1000).fill(0)创建一个1000大小的零数组
let a=new Array(1000).fill(0);
a[1]=1;
let fib = function(n) {
if(n==0){
return 0;
}
//如果a[n]存在 就直接返回a[n]
if(a[n]!=0) return a[n];
//没存在就递归计算
a[n] = (fib(n-1)+fib(n-2))%1000000007;
return a[n];
};
// 3.动态规划1
/**
* @param {number} n
* @return {number}
*/
let fib = function(n) {
let a=0,b=1,sum;
if(n==0)
return a;
if(n==1)
return b;
for(let i = 0 ; i<n-1 ; i++ )
{
sum=(a+b)%1000000007;
a=b;
b=sum
}
return sum;
};
// // 4.动态规划2
/**
* @param {number} n
* @return {number}
*/
let fib = function(n) {
let a=0,b=1,sum;
for(let i = 0 ; i<n ; i++ )
{
sum=(a+b)%1000000007;
a=b;
b=sum
}
return a;
};
// 4.动态规划3
/**
* @param {number} n
* @return {number}
*/
let fib = function(n) {
//用new Array()来生成指定大小的数组
let dp= new Array(n+1);
dp[0]=0;
dp[1]=1;
for(let i = 2 ; i<=n ; i++ )
{
dp[i]=dp[i-1]+dp[i-2];
dp[i]%=1000000007;
}
return dp[n];
};
四、拓展思考
这里我们就来讨论下我给出的动态规划思想解题的1,2,3代码逻辑的的区别:
动态规划1 : 动态规划1的代码i循环n-1次,因为其实算fib(n)只需要n-1次计算,且n-1次计算之后答案就是sum(所以return sum),但是要注意的是,要讨论n==0和n==1的特殊情况,这就是i<n-1(循环n-1次)所带来的其他麻烦。
动态规划2 : 动态规划2的代码i循环n次,可以发现n次计算之后答案赋给了a(所以return a),相比于动态规划1更方便的是这里不要讨论n的值,缺点是多循环了一次。
动态规划3 : 动态规划3的代码其实才可以算作是动态规划,直接new一个大小为n+1(因为答案就为dp[n],所以数组大小为n+1)的dp数组,且dp[0]=0,dp[1]=1,然后i循环n次,直接通过dp[i]=dp[i-1]+dp[i-2]得到最后的答案dp[n]。(而且也不用考虑初值,因为dp[0]和dp[1]以及被提前赋值好了!)
最后一定记得要%1000000007,细节决定成败!
题目来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/fe…