欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

200928剑指Offer学习总结:斐波那契数列

程序员文章站 2023-12-26 23:59:09
...

200928算法学习总结:斐波那契数列

1. 原题目:

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

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

2. 题目分析

我们都知道,传统的递归方式十分耗时,本题中不能直接使用这种方式,会超时。因此我们可以有两种方式进行优化:

(1)非递归方式

a、b分别表示数列中第一个和第二个数,for循环循环n次,每次sum都等于a、b的和,然后a的值来自于b,b的值来自于sum,如此循环,我们最终得到的第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;
    }
}

优化:可以不用sum中间数,直接使用a、b两个数循环。

class Solution {
    public int fib(int n) {
        int ans0=0,ans1=1;//分别代表第一个数、第二个数,
        if(n==0||n==1){
            return n;
        }
        for(int i=0;i<n;i++){
            ans1=ans1+ans0;//1 2 3 5 8 13
            ans0=ans1-ans0;//1 1 2 3 5 8 
            ans1%=1000000007;
        }
        return ans0;
    }
}

(2)优化的递归方式

正如前面说的,递归会超时,那么为什么会这样呢?事实上我们可以想到递归是如何计算的:

200928剑指Offer学习总结:斐波那契数列

如上图所示,在递归计算中会重复计算很多值,比如从F6向下计算F5和F4时,F5递归计算F4和F3,这时F4就被重复计算了,那么我们只需要把计算过的值记录下来,后面遇到同样的计算时直接把值传过去、不再计算,这样就能降低时间复杂度。

存储时可以使用map,如下。也可以使用数组,这种方法需要额外的空间。

public int fib(int n, Map<Integer, Integer> map) {
    if (n < 2)
        return n;
    if (map.containsKey(n))
        return map.get(n);
    int first = fib(n - 1, map) % 1000000007;
    map.put(n - 1, first);
    int second = fib(n - 2, map) % 1000000007;
    map.put(n - 2, second);
    int res = (first + second) % 1000000007;
    map.put(n, res);
    return res;
}

图片及map代码出处:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/solution/di-gui-he-fei-di-gui-liang-chong-fang-shi-du-ji-ba/

3. 总结

递归的优化(记忆化的递归)方式,能够避免递归中的重复计算。

4. 拓展:青蛙跳台阶问题

剑指 Offer 10- II. 青蛙跳台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:2

示例 2:

输入:n = 7
输出:21

示例 3:

输入:n = 0
输出:1

提示:

  • 0 <= n <= 100

这道题是一个斐波那契数列的变形,有两点不同:

  1. 特殊要求第零项是1,而不是0,但是我们为了使用斐波那契的规律,依然在计算时把第零项当作0,然后最后的结果上我们加1。
  2. 得到的到达第n个台阶情况是前面所有斐波那契数的和,最后要求和。

代码如下。

class Solution {
    public int numWays(int n) {
        int ans0=0,ans1=1;//分别代表第一个数、第二个数,
        int ans2=1;//最终结果
        if(n<=1){
            return 1;
        }
        
        for(int i=0;i<n;i++){//从n=1开始
            ans2+=ans0;   //       3 5 8 13 21
            ans2%=1000000007;

            ans1=ans1+ans0;//1 1   1 2 3 5 8 13
            ans0=ans1-ans0;//      1 1 2 3 5 8 

            ans1%=1000000007;
        }
        return ans2;
    }
}

上一篇:

下一篇: