写一个函数,输入 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
1、原始递归,超时
我在网上还看到一种递归解法,就是每次递归的时候额外带一个辅助空间,递归时算出来的数存到辅助空间里,下一次递归时还能用到,这种递归其实也算是一种动态规划思想。
class Solution {
public int fib(int n) {
if(n<2){
return n;
}
return (fib(n-1)+fib(n-2))%1000000007;
}
}
2、动态规划
哪些问题适用动态规划:
- 有重叠子问题
- 具有最优子结构
- 无后效性:这个状态之后的过程不会影响到这个已经用完的状态
动态规划解题步骤:
- 拆解问题并找到子问题之间联系
- 定义初始状态
- 确定状态转移方程
- 确定边界条件并实现
class Solution {
public int fib(int n) {
if(n<2) return n;
int[] dp=new int[n+1];
dp[0]=0;
dp[1]=1;
for(int i=2;i<=n;i++){
dp[i]=(dp[i-1]+dp[i-2])%1000000007;
}
return dp[n];
}
}
3、动态规划优化
优化动态规划一般是优化空间,依据公式dp[i]=dp[i-1]+dp[i-2],可知要计算的数只与前两个数相关,所以可以不使用数组,使用三个变量就行。
class Solution {
public int fib(int n) {
if(n<2) return n;
int first=0;
int second=1;
for(int i=2;i<=n;i++){
int sum=(first+second)%1000000007;
first=second;
second=sum;
}
return second;
}
}