写一个函数,输入 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
斐波那契数列 算是老朋友了,都知道用递归的方式能够解决,但是递归方式将问题分成一个一个小问题,进行递归调用,但其中有重复的部分。如下图:
这些重复部分会拖慢程序运行的速度,那么我们是否可以将f(n-1) 和 f(n-2)的值存起来当需要f(n)时直接取出相加,这样就会极大的提高速度,并且去除掉冗余的部分。
首先进行动态规划说白了就是:要存储我们之前计算的信息,避免我们重复计算。所以我们需要进行对数据的存储(一维数组,二维数组等),大部分都是二维数组的题目。
有三个步骤:1 定义数组元素的含义 在这道题中定义arr[i]代表的是存储的计算结果
2 找出数组元素的关系式 在这道题中明显给出f(nf(n-1)+f(n-2) (关键)
3 确定初始条件 在这道题中就是 f(0)=0; f(1)=1;
4 确认初始化(重复第三步)初始值要严谨
所以这道题的题解为:
class Solution {
public int fib(int n) {
//递归 调用时间长 超时
//动态规划
//1.定义数组元素的含义
//2 找出数组元素间的关系式
//3 找到初始条件
//4 确定初始化
if(n<=1) return n;
int[] arr=new int[n+1];//数组从零开始 ,例如 n=10 就要加11个数从零开始
arr[0]=0;
arr[1]=1;
for(int i=2;i<=n;i++){
arr[i]=arr[i-1]+arr[i-2];//从 i等于2开始 一个一个往里面存
arr[i]%=(1000000007);
}
return arr[n];
}
}
例二:
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:输入:n = 7
输出:21
示例 3:输入:n = 0
输出:1
提示:0 <= n <= 100
class Solution {
public int numWays(int n) {
//动态规划
//1 确定数组存的内容 dp[i] 是指小青蛙走台阶的做法
//2 确定i 之间存在的关系 他可以走一层台阶 也可以走两层台阶 那么 dp[i]=dp[i-1]+dp[i-2];因为有两种走法
//3 确定初始值 当没有台阶时 和 只有一节台阶时,只有一种走法,当台阶有2层时 有两种走法
if(n<=1) return 1;
if(n==2) return n;
int[] arr=new int[n+1];
arr[0]=1;
arr[1]=1;
arr[2]=2;
for(int i=3;i<=n;i++){
arr[i]=arr[i-1]+arr[i-2];//存在一个数组中 ,最后返回值
arr[i]%=1000000007;
}
return arr[n];
}
}
重复上面的几步:
(1)确定数组存的内容 arr[i]存的是小青蛙走台阶的走法
(2)确定数组元素间的关系式 小青蛙在第n层台阶时,它一共有f(n-1) +f(n-2)种走法,因为它可以在开始只跳一层台阶( f(n-1)),也可以跳两层台阶( f(n-2)),所以关系式为:arr[i]=arr[i-1]+arr[i-2]
(3)确定初始条件 当有0阶台阶时 有一种跳法 ;当有1阶台阶时 有一种跳法 ;当有两阶台阶时有两种跳法。
(4)重复初始化