【剑指offer】07——斐波那契数列

题目描述

  大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39

一、斐波那锲数列

  • 指的是这样一个数列: 1 、 1 、 2 、 3 、 5 、 8 、 13 、 21 、 34 、 … … 1、1、2、3、5、8、13、21、34、…… 112358132134

  • 在数学上,斐波纳契数列以如下被以递推的方法定义: F ( 1 ) = 1 , F ( 2 ) = 1 , F ( n ) = F ( n − 1 ) + F ( n − 2 ) ( n &gt; = 3 , n ∈ N ∗ ) F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n&gt;=3,n∈N*) F(1)=1F(2)=1,F(n)=F(n1)+F(n2)n>=3nN

f ( n ) = { 0 n = 0 1 n = 1 f ( n − 1 ) + f ( n − 2 ) n &gt; 1 f(n)=\begin{cases} 0 &amp;n=0\\ 1&amp;n=1\\ f(n-1)+f(n-2) &amp; n&gt;1 \end{cases} f(n)=01f(n1)+f(n2)n=0n=1n>1

二、解题思路

本题根据数学公式很容易想到用递归的方法:

public class Solution {
    public int Fibonacci(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1){
            return 1;
        }
        return Fibonacci(n-1) + Fibonacci(n-2);  //递归调用
    }
}

在这里插入图片描述

从上图很容易看出,这种方法的运行时间比较长,我们仔细分析下,如果我们要计算 f ( 10 ) f(10) f(10),就要计算 f ( 9 ) f(9) f(9) f ( 8 ) f(8) f(8),计算 f ( 9 ) f(9) f(9),就要计算 f ( 8 ) f(8) f(8) f ( 7 ) f(7) f(7),可以发现,这里 f ( 8 ) f(8) f(8) 被重复计算了,随着 n n n 的增大,需要重复计算的急剧增加,这意味着计算量也会随着 n n n 的增大而急剧增大。

在这里插入图片描述

  为了避免重复计算,最好的方法就是,我们将已经计算好的项先保存起来,在下次计算的时候,我们先查找下,如果前面已经计算过了就不用再重复计算了。

  递归是将一个问题划分成为多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复计算。

public class Solution {
    public int Fibonacci(int n) {
        if(n <= 1){
            return n;
        }
        
        int[] result = new int[n + 1];  //存储每项结果,填充0
        result[1] = 1;
        
        for(int i = 2; i <= n; i++){
            result[i] = result[i - 1] + result[i - 2];
        }
        return result[n];
    }
}

在这里插入图片描述

相比递归的方法,此方法运行时间大大减少,因为要存储所有的计算结果,此时的空间复杂度为 O ( n ) O(n) O(n)

  进一步我们根据公式可以发现,第 n n n 项,只与第 n − 1 n-1 n1 项和第 n − 2 n-2 n2 项有关,因此我们只需要存储前面两项的值就可以,这样空间复杂度由 O ( n ) O(n) O(n) 降低的 O ( 1 ) O(1) O(1)

public class Solution {
    public int Fibonacci(int n) {
        if(n <= 1){
            return n;
        }
        int[] tmp = {0, 1};  //存储前两次结果
        int result = 0;  //本次结果
        for(int i = 2; i <= n; i++){
            result = tmp[0] + tmp[1];
            //更新前两次结果
            tmp[0] = tmp[1];
            tmp[1] = result;
        }
        
        return result;
    }
}

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

三、Java 代码

public class Solution {
    public int Fibonacci(int n) {
        if(n <= 1){
            return n;
        }
        int[] tmp = {0, 1};  //存储前两次结果
        int result = 0;  //本次结果
        for(int i = 2; i <= n; i++){
            result = tmp[0] + tmp[1];
            //更新前两次结果
            tmp[0] = tmp[1];
            tmp[1] = result;
        }
        
        return result;
    }
}

四、C++ 代码

class Solution {
public:
    int Fibonacci(int n) {
        if(n <= 1){
            return n;
        }
        
        int tmp[] = {0, 1};
        int result = 0;
        
        for(int i = 2; i <= n; i++){
            result = tmp[0] + tmp[1];
            
            tmp[0] = tmp[1];
            tmp[1] = result;
        }
        
        return result;
    }
};

五、Python3 代码

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n <= 1:
            return n
        tmp = [0, 1]
        result = 0
        for i in range(2, n + 1):
            result = tmp[0] + tmp[1]
            tmp[0] = tmp[1]
            tmp[1] = result
        return result
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值