【剑指 Offer_10- I】斐波那契数列_Python&Java_动态规划解法

题目描述

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

方法一、动态规划

参考面试题10- I. 斐波那契数列(动态规划,清晰图解)
因为数列前后数具有一定的关联,所以斐波那契数列是可以使用动态规划的思路来解答的。

大数越界问题: 随着 n 增大, f(n)会超过 Int32 甚至 Int64 的取值范围,导致最终的返回值错误。

求余运算规则: 设正整数 x, y, p,求余符号为⊙ ,则有 (x + y)⊙p = (x⊙p + y⊙p)⊙p

解析: 根据以上规则,可推出 f(n)⊙p=[f(n−1)⊙p+f(n−2)⊙p]⊙p ,从而可以在循环过程中每次计算 sum=(a+b)⊙1000000007。

Python解法

由于 Python 中整形数字的大小限制 取决计算机的内存 (可理解为无限大),因此可不考虑大数越界问题。同时,可省去sum辅助变量的设置。
_占位符,表示只在意循环次数,不在意变量值。

class Solution:
    def fib(self, n: int) -> int:
        a, b = 0, 1
        for _ in range(n):#for i in range(n):这样写就ok
            a, b = b, a + b
        return a % 1000000007

不妨试一试:n = 5
n = 0,a,b = 1,1
n = 1 , a,b = 1,2
n = 2, a,b = 2,3
n = 3 , a,b = 3,5
n = 4 , a,b = 5,8
返回a = f(5) = 5
执行用时:40 ms, 在所有 Python3 提交中击败了64.84%的用户
内存消耗:13.5 MB, 在所有 Python3 提交中击败了13.55%的用户

Java解法1

以一个数组来存储每次获取的fib(n)的值,更容易理解。

class Solution {
    public int fib(int n) {
        if(n == 0) return 0;
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2; i <= n; i++){
            dp[i] = dp[i-1] + dp[i-2];
            dp[i] %= 1000000007;
        }
        return dp[n];
    }
}

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.2 MB, 在所有 Java 提交中击败了86.67%的用户

复杂度分析

时间复杂度 O(N) : 计算 f(n)需循环 n次,每轮循环内计算操作使用 O(1)。
空间复杂度 O(N): 数组作为额外空间。

java解法2

用sum值存储num1+num2 最后返回sum,其实有的时候返回什么,可以根据算法演算一下,再确定比较稳妥一些。

class Solution {
public int fib(int n) {
    if(n==0)
        return 0;
    if(n==1)
        return 1;

    int num1=0,num2=1,sum=0;
    while(n>=2){
        sum=(num1+num2)%1000000007 ;//题目要求
        num1=num2;
        num2=sum;
        n--;
    }
    return sum;
    }
};

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.2 MB, 在所有 Java 提交中击败了84.89%的用户

java解法3

这种解法跟python解法是相同的。
a,b代表相邻两个斐波那契数;a是前一个,b是后一个。经过一次迭代后a代表fib(1)的值,两次迭代后a代表fib(2)的值,因此经过n次迭代a代表的是fib(n)的值,因此返回a才是正确结果~

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

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.3 MB, 在所有 Java 提交中击败了78.74%的用户

复杂度分析

时间复杂度 O(N) : 计算 f(n)需循环 n次,每轮循环内计算操作使用 O(1)。
空间复杂度 O(1): 几个标志变量使用常数大小的额外空间。

总的来说比较推荐Java解法1,容易理解一些。其他解法是一个原理,要稍微绕一绕。

以上就是全部内容了,你觉得可以理解吗?欢迎评论~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂java杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值