斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/fibonacci-number
递归的方法很好理解:当n=0,那就返回0,当n=1,那就返回1,其余的都用前两个想加得出。
- class Solution {
- public int fib(int n) {
- if (n == 0){
- return 0;
- }
- if (n == 1){
- return 1;
- }
- return fib(n - 1) + fib( n - 2);
- }
- }
效果不好,不推荐这种方法
这道题可以说是动态规划问题中比较简单的题,用动态规划来解题也是非常的方便。
这道题很适合 入门学习动态规划问题,因为题目已经将递推公式告诉我们了,很好写出来。
动态规划 三步走
动态规划,就是利用历史记录,来避免我们的重复计算。而这些历史记录,我们得需要一些变量来保存,一般是用一维数组或者二维数组来保存。下面我们先来讲下做动态规划题很重要的三个步骤,
1.定义dp数组
我们会用一个数组,来保存历史数组,假设用一维数组 dp[] 吧。这个时候有一个非常重要的点,就是规定你这个数组元素的含义,例如你的 dp[i] 是代表什么意思?
2.找出递推关系式
动态规划类似于高中数学的数学归纳法,当我们要计算 dp[n] 时,是可以利用 dp[n-1],dp[n-2]…..dp[1],来推出 dp[n] 的,也就是可以利用历史数据来推出新的元素值,所以我们要找出数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],这个就是他们的关系式了。
3.找出初始值
找出了递推公式,我们还需要初始值,因为递推公式就是靠前面的值推出后面的值,但总得有个头吧,这个头就是初始值。
提示
代码如何排错?将dp数组全部输出看看
1:dp数组:存储斐波那契计算结果
2:递推公式:题目直接给你了
3:初始值:dp[0]=0,dp[1]=1
- 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 < dp.length; i++) {
- dp[i] = dp[i - 1] + dp[i - 2];
- }
- return dp[n];
- }
- }
可以看到效果比递归好了不少,动态规划 win!
从方法2的动态规划中我们不难发现:每个数都是由它前两个数得出的,所以我们不用维护整个数组,我们只需要维护长度为3的数组即可。
- class Solution {
- public int fib(int n) {
- if (n < 2) {
- return n;
- }
- int num1 = 0;
- int num2 = 1;
- int sum = num1 + num2;
-
- for (int i = 2; i <= n; i++) {
- sum = num1 + num2;
- num1 = num2;
- num2 = sum;
- }
- return sum;
- }
- }