剑指 Offer 10- I. 斐波那契数列 | 刷题打卡

138 阅读2分钟

题目

描述

写一个函数,输入 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

思路

F(0) = 0, F(1) = 1

F(N) = F(N - 1) + F(N - 2), 其中 N > 1

利用递归的方法, 把 f(n)f(n) 问题的计算拆分成 f(n1)f(n−1)f(n2)f(n−2) 两个子问题的计算,并递归,以 f(0)f(0)f(1)f(1) 为终止条件,虽然能求出结果,但是最终会超时;

实现

class Solution {
    public int fib(int n) {
        if (n == 0 || n == 1) {
            return n;
        }
        
        return (fib(n - 1) + fib(n - 2)) % 1000000007;
    }
}

方法 2

思路

3.2.1 思路

减少暴力递归中的重复运算,可以将子问题的答案存放到备忘录,进行下次运算时先从备忘录中查询,如果已经有对应答案,直接取出用就行,这样就可以大大减少运算的时间。

通过添加备忘录,将原来的递归树进行了剪枝,大大减少了子问题,此时的子问题个数变成了 nn,此时的时间复杂度变成了 O(n)O(n)

实现

class Solution {
    // 用一个哈希表来当备忘录
    HashMap<Integer, Integer> hashMap = new HashMap<>();

    public int fib(int n) {
        // Base Case
        if (n == 0 || n == 1) {
            return n;
        }

        // 如果计算过了,就直接返回对应答案
        if (hashMap.containsKey(n)) {
            return hashMap.get(n);
        } else {
            // 没计算过的进行计算,同时存入备忘录
            int val =( fib(n - 2) + fib(n - 1)) % 1000000007;
            hashMap.put(n, val);
            return val;
        }
    }
}

方法 3

思路

F(0) = 0, F(1) = 1

F(N) = F(N - 1) + F(N - 2), 其中 N > 1

利用上述条件,利用动态规划的思想;

  • 状态定义: 设 dpdp 为一维数组,其中 dp[i]dp[i] 的值代表 斐波那契数列第 ii 个数字 。
  • 转移方程dp[i+1]=dp[i]+dp[i1]dp[i + 1] = dp[i] + dp[i - 1],即对应数列定义 f(n+1)=f(n)+f(n1)f(n + 1) = f(n) + f(n - 1)
  • 初始状态dp[0]=0dp[0] = 0, dp[1]=1dp[1]=1 ,即初始化前两个数字;
  • 返回值dp[n]dp[n] ,即斐波那契数列的第 nn 个数字
  • 时间复杂度:此时主要进行循环操作,时间复杂度为 O(n)O(n)

实现

public int fib(int n) {
    if(N == 0 || N == 1){
        return N;
    }

    int prev = 0;
    int curr = 1;
    for(int i = 2; i <= N; i++){
        int sum = (prev + curr) % 1000000007;
        prev = curr;
        curr = sum;
    }

    return curr;

}

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情