剑指 Offer 10- I. 斐波那契数列

题目:剑指 Offer 10- I. 斐波那契数列

写一个函数,输入 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
链接:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/

// 方法一:递归暴力请求,效率低下(原因:大量重复计算子问题)
// 方法二:带有备忘录的求解
// 方法三:dp数组的迭代解法

解题:

package com.learn.science.algorithm.zhijian.dp;

import io.swagger.models.auth.In;

import java.util.HashMap;
import java.util.Map;

/**
 * @author ZMJ
 * @date 2021/2/7
 */
public class DPZ101fib {
     

    /**
     剑指 Offer 10- I. 斐波那契数列
     写一个函数,输入 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

     1 1 2 3 5 8 13 ... 
     */
    // 方法一:递归暴力请求,效率低下(原因:大量重复计算子问题)
    public static int fib_dg(int n) {
     
        if (n == 0 || n == 1) {
     
            return n;
        }
        return fib_dg(n - 1) + fib_dg(n -2);
    }
    // 方法二:带有备忘录的求解
    // 思想:将重复计算优化掉
    // 使用备忘录,将结果子问题记录,解决问题先去查是否处理过子问题,如果处理过直接拿结果,如果没有在处理,处理完存入备忘录;
    public static int fib_bwl(int n) {
     
        if (n < 1) {
     
            return 0;
        }
        // 备忘录全初始化为 0
        Map<Integer, Integer> memo = new HashMap<>();
        // 进行带备忘录的递归
        return fib_bwl_dg(memo, n);
    }
    public static int fib_bwl_dg(Map<Integer, Integer> memo, int n) {
     
        // base case
        if (n == 1 || n == 2) {
     
            return 1;
        }
        // 已经计算过
        if (memo.get(n) != null) {
     
            return memo.get(n);
        }
        // 没计算过计算
        int result = fib_bwl_dg(memo, n - 1) + fib_bwl_dg(memo, n - 2);
        // 存储备忘录
        memo.put(n, result);

        return memo.get(n);
    }
    // 方法三:dp数组的迭代解法
    // 思想:有了上面的备忘录解法,我们可以把这个「备忘录」独立出来成为一张表,就叫做 DP table 吧,在这张表上完成「自底向上」的推算
    public static int fib_dp(int n) {
     
        if (n < 1) {
     
            return 0;
        }
        if (n == 1 || n == 2) {
     
            return 1;
        }
        // dp初始化
        Map<Integer, Integer> dp = new HashMap<>();
       // base case
        dp.put(1, 1);
        dp.put(2, 1);
        for (int i = 3; i <= n; i ++) {
     
            dp.put(i, dp.get(i - 1) + dp.get(i - 2));
        }
        return dp.get(n);
    }

    // 方法四:基于dp的状态压缩
    // 因为此题不是最值问题,不需要记录全部状态,只需要记录前两个状态即可;所以可以将状态记录的DPtable压缩;
    public static int fid_ztys(int n) {
     
        if (n < 1) {
     
            return 0;
        }
        if (n == 1 || n == 2) {
     
            return 1;
        }
        int per1 = 1, per2 = 1; // 前面两个值,不需要全部的状态值,这个只需要记录两个状态值。
        int sum = 0;
        for (int i = 3; i <= n; i ++) {
     
            sum = per1 + per2;
            per1 = per2;
            per2 = sum;
        }
        return sum;
    }

    public static int fib(int n) {
     
        int a = 0, b = 1, sum;
        for (int i = 0; i < n; i ++) {
     
            // sum = a + b;
            sum = (a + b)%1000000007;
            a = b;
            b = sum;
        }
        return a;
    }

    public static void main(String[] args) {
     
        System.out.println(fid_ztys(10));

    }
}

你可能感兴趣的:(Leetcode-算法,leetcode,算法,java)