本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目:斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1.F(n) = F(n - 1) + F(n - 2),其中 n > 1。给你 n ,请计算 F(n) 。
二、解析
这是一道经典的递归题目,但是通过递归的方式解题,会发现有很多重复的计算。比如计算F(4)时,F(4)=F(3)+F(2), F(3)=F(2)+F(1)... 明显看出,F(2)在这个过程计算了两次。通过递归的算法其时间复杂度是2^n。
再看斐波那契数列的生成规则,能发现其非常使用动态规划方法来解题。每一个F(n)都由F(n - 1) 和 F(n - 2)推导而来,而动态规划也是解决“每一个状态一定是由上一个状态推导出来”一类的问题(这一点可以区别于贪心算法,贪心算法只追求每一步的最优解,而不需考虑上一个状态)。
动态规划(dp)有三要素:最优子结构、状态转移方程、边界。在本题中:
- F(n - 1) 和 F(n - 2) 是F(n)的最优子结构
- F(n) = F(n - 1) + F(n - 2) 是状态转移方程
- F(0) = 0 和 F(1) = 1 是边界
确定三要素之后,还要确定遍历顺序。这里如果还是从N向0遍历,还是会产生重复计算的情况,因此应采用0向N遍历。
在解题过程中,遇上复杂的题目,有时可能需要做很多的debug。通过举例推导dp数组,可以更加直观得到结果我们推导的是否一致。如这里,当N=10时,dp数组应该是 0 1 1 2 3 5 8 13 21 34 55。
三、代码
class Solution {
public int fib(int n) {
int f0 = 0;
int f1 = 1;
if(n < 2){
return n;
}
for(int i = 2; i <= n; i++){
f1 = f1 + f0;
f0 = f1 - f0;
}
return f1;
}
}
相似题目: 70.爬楼梯