动态规划一:斐波那契数 | Java 刷题打卡

194 阅读2分钟

本文正在参加「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.爬楼梯