【LeetCode】动态规划—斐波那契数列(附完整Python/C++代码)

前言

这道题目是经典的 斐波那契数列 问题。题目要求给定一个整数 n n n ,返回第 n n n 个斐波那契数。

斐波那契数列的定义是:

  • F ( θ ) = θ F(\theta)=\theta F(θ)=θ
  • F ( 1 ) = 1 F(1)=1 F(1)=1
  • 对于 n > = 2 , F ( n ) = F ( n − 1 ) + F ( n − 2 ) n>=2, F(n)=F(n-1)+F(n-2) n>=2,F(n)=F(n1)+F(n2)

递推关系:
和爬楼梯问题类似,我们可以通过递推公式 F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n1)+F(n2) 来计算第 n n n 个斐波那契数。

LeetCode是一个广受欢迎的在线编程平台,专注于算法和数据结构的练习。它提供了数千道编程题目,涵盖从简单到困难的各种难度,帮助程序员提升解决问题的能力,准备技术面试,并加深对计算机科学基础知识的理解。
通过逐步解析不同类型的题目,希望能够帮助读者更好地理解算法的应用,掌握解题技巧,并提高编程能力。每篇文章将围绕特定的主题或算法展开,提供详细的解题思路以及代码实现。

题目描述

在这里插入图片描述

基本思路

1. 斐波那契数列的定义

斐波那契数列是一个从 0 开始的数列,后面的每一项是前两项的和:

  • 第 0 项是 0 : F ( θ ) = 0 0: F(\theta)=0 0:F(θ)=0
  • 第1项是 1: F ( 1 ) = 1 F(1)=1 F(1)=1
  • 从第 2 项开始,每一项的值都是前两项的和:
  • F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n1)+F(n2), 其中 n > = 2 n>=2 n>=2

2. 理解递推关系

假设我们想计算第 n n n 项的斐波那契数 F ( n ) F(n) F(n) ,我们可以利用递推关系:

  • 先知道 F ( n − 1 ) F(n-1) F(n1) F ( n − 2 ) F(n-2) F(n2)
  • 然后通过公式 F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n1)+F(n2) 计算出 F ( n ) F(n) F(n)

举个例子:

  • F ( 2 ) = F ( 1 ) + F ( 0 ) = 1 + θ = 1 F(2)=F(1)+F(0)=1+\theta=1 F(2)=F(1)+F(0)=1+θ=1
  • F ( 3 ) = F ( 2 ) + F ( 1 ) = 1 + 1 = 2 F(3)=F(2)+F(1)=1+1=2 F(3)=F(2)+F(1)=1+1=2
  • F ( 4 ) = F ( 3 ) + F ( 2 ) = 2 + 1 = 3 F(4)=F(3)+F(2)=2+1=3 F(4)=F(3)+F(2)=2+1=3
  • F ( 5 ) = F ( 4 ) + F ( 3 ) = 3 + 2 = 5 F(5)=F(4)+F(3)=3+2=5 F(5)=F(4)+F(3)=3+2=5

3. 递归方法(直观但效率低)

初学者可能会想到使用递归,即不停地调用 F ( n − 1 ) F(n-1) F(n1) F ( n − 2 ) F(n-2) F(n2) 来得到结果。这是最直观的想法,但它的效率不高,因为很多计算会被重复执行。比如计算 F ( 5 ) F(5) F(5) 时,会重复计算 F ( 3 ) 、 F ( 2 ) F(3) 、 F(2) F(3)F(2) 等。

int fib(int n) {
    if (n == 0) return 0;
    if (n == 1) return 1;
    return fib(n-1) + fib(n-2);
}

4. 动态规划方法 (高效)

为了解决递归中重复计算的问题,我们可以用动态规划,即从底向上计算,先计算小的数值,逐步推导出大的数值。

我们可以用一个数组来存储已经计算过的斐波那契数,从 F ( θ ) F(\theta) F(θ) F ( 1 ) F(1) F(1) 开始,一步步推导到 F ( n ) F(n) F(n)

步骤:

  1. d p [ i ] \mathrm{dp}[\mathrm{i}] dp[i] 表示第 i 个斐波那契数。
  2. 初始化前两项: d p [ θ ] = θ , d p [ 1 ] = 1 d p[\theta]=\theta, d p[1]=1 dp[θ]=θ,dp[1]=1
  3. 从第 2 项开始,依次计算: d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] d p[i]=d p[i-1]+d p[i-2] dp[i]=dp[i1]+dp[i2] ,直到 i = n i=n i=n
  4. 返回 d p [ n ] d p[n] dp[n]

这种方法不会有重复计算,因此效率非常高。

5. 进一步优化: 只用常量空间

其实我们不需要一个数组来存储所有的斐波那契数。因为在计算第 n n n 项时,我们只需要前两项 F ( n − F(n- F(n 1) 和 F ( n − 2 ) F(n-2) F(n2) ,所以我们可以只用两个变量来记录这两项,不断向前推导。

步骤:

  1. 先设置两个变量: prev1 = 1 =1 =1 和 prev2 = 0 =0 =0 ,分别对应 F ( 1 ) F(1) F(1) F ( θ ) F(\theta) F(θ)
  2. 从第 2 项开始,逐步计算当前的斐波那契数 current = prev1 + prev2,然后更新 prev1 和 prev2 。
  3. 继续这个过程,直到算到第 n 项。

小总结:

  • 斐波那契数列的每一项是前两项的和,定义明确,可以用递归或动态规划解决。
  • 递归方法直观但效率低,会有很多重复计算。
  • 动态规划方法通过从小到大计算并存储中间结果,避免了重复计算,大大提高了效率。
  • 空间优化方法只需要常量的空间存储前两项的值,是动态规划的进一步优化。

这就是斐波那契数列问题的基本思路。

代码实现

Python3代码实现

class Solution:
    def fib(self, n: int) -> int:
        # 如果 n 是 0 或 1,直接返回 n
        if n == 0:
            return 0
        elif n == 1:
            return 1
        
        # 使用两个变量来存储前两个斐波那契数,prev2 是 F(n-2),prev1 是 F(n-1)
        prev2, prev1 = 0, 1
        
        # 计算从 F(2) 到 F(n) 的值
        for i in range(2, n + 1):
            # 当前的斐波那契数是前两个数的和
            current = prev1 + prev2
            # 更新前两个数,继续计算下一个
            prev2 = prev1
            prev1 = current
        
        # 最后 prev1 中保存的是 F(n)
        return prev1

Python 代码解释

  1. Base Case: 如果 n = = 0 n==0 n==0 n = = 1 n==1 n==1, 直接返回 n n n ,因为 F ( 0 ) = 0 , F ( 1 ) = 1 F(0)=0, F(1)=1 F(0)=0,F(1)=1
  2. 动态规划:使用两个变量 prev2 和 prev1 来存储前两个斐波那契数,避免使用数组来节省空间。
  3. 循环:从 2 到 n 逐步计算斐波那契数,当前的值等于前两个值的和,然后更新 prev2 和 prev1 。
  4. 最终结果: prev1 最终会存储 F ( n ) F(n) F(n)

C++代码实现

class Solution {
public:
    int fib(int n) {
        // 如果 n 是 0 或 1,直接返回 n
        if (n == 0) return 0;
        if (n == 1) return 1;
        
        // prev2 保存 F(n-2),prev1 保存 F(n-1)
        int prev2 = 0, prev1 = 1, current = 0;
        
        // 从 F(2) 到 F(n) 逐步计算
        for (int i = 2; i <= n; ++i) {
            // 当前的斐波那契数是前两个数的和
            current = prev1 + prev2;
            // 更新前两个斐波那契数
            prev2 = prev1;
            prev1 = current;
        }
        
        // 返回第 n 个斐波那契数
        return current;
    }
};

C++ 代码解释

  1. Base Case: 如果 n = = 0 n==0 n==0 n = = 1 n==1 n==1, 直接返回 n n n
  2. 动态规划: 使用 prev2 和 prev1 变量存储前两个斐波那契数,以节省空间,不使用数组。
  3. 循环:从 2 到 n 逐步计算每个斐波那契数,当前值等于 prev1 + prev2,然后更新这两个变量。
  4. 返回结果: 最终 current 存储了 F ( n ) F(n) F(n) ,并返回该值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Albert_Lsk

今天又能喝柠檬茶啦

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

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

打赏作者

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

抵扣说明:

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

余额充值