力扣:509. 斐波那契数(动态规划,附带递归版本) 详细讲解动态规划的思路

news/2024/6/1 22:48:35 标签: leetcode, 动态规划, 算法, 数据结构, python

题目:

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。

示例 1:

输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:

输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:

输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3

提示:

0 <= n <= 30

思路:

本题很简单,但很适合用来做动态规划(和递归)的入门题,本篇文章主要讲解一下动态规划的思路

动态规划

动规五部曲:

这里我们要用一个一维dp数组来保存递归的结果

  1. 确定dp数组以及下标的含义

dp[i]的定义为:第i个数的斐波那契数值是dp[i]

  1. 确定递推公式

为什么这是一道非常简单的入门题目呢?

因为题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];

  1. dp数组如何初始化

题目中把如何初始化也直接给我们了,如下:

python">        dp[0] = 0
        dp[1] = 1
  1. 确定遍历顺序

从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的

  1. 举例推导dp数组

按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:

0 1 1 2 3 5 8 13 21 34 55

如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。

以上就是动态规划五部曲 这在之后将贯穿所有动态规划类的题目

完整代码和复杂度分析:

动态规划版本1(定义dp数组):

python">class Solution:
    def fib(self, n: int) -> int:
       
        # 排除 Corner Case
        if n == 0:
            return 0
        
        # 创建 dp table 
        dp = [0] * (n + 1)

        # 初始化 dp 数组
        dp[0] = 0
        dp[1] = 1

        # 遍历顺序: 由前向后。因为后面要用到前面的状态
        for i in range(2, n + 1):

            # 确定递归公式/状态转移公式
            dp[i] = dp[i - 1] + dp[i - 2]
        
        # 返回答案
        return dp[n]
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

动态规划版本2(不自定义dp数组,仅使用3个变量来维护dp数组):

python">class Solution:
    def fib(self, n: int) -> int:
        if n <= 1:
            return n
        
        dp = [0, 1]
        
        for i in range(2, n + 1):
            total = dp[0] + dp[1]
            dp[0] = dp[1]
            dp[1] = total
        
        return dp[1]
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

递归版本:

python">class Solution:
    def fib(self, n: int) -> int:
        if n < 2:
            return n
        return self.fib(n - 1) + self.fib(n - 2)
  • 时间复杂度:O(2^n)
  • 空间复杂度:O(n)

http://www.niftyadmin.cn/n/5293891.html

相关文章

[音视频 ffmpeg] 复用推流

获取摄像头demo videodecodethread.cpp #include "videodecodethread.h"VideodecodeThread::VideodecodeThread(QObject *parent):QThread(parent) {avdevice_register_all();avformat_network_init(); }VideodecodeThread::~VideodecodeThread() {if(pFormatCtx){a…

Error in onLoad hook: “URIError: URI malformed“ found in…报错处理以及完善uniapp针对对象传参

使用uniapp传参的过程中遇到这么一个问题&#xff0c;当我们需要传整个对象作为参数时&#xff0c;我会先将这个对象先编码&#xff0c;然后再解码&#xff0c;从而获取到怎么参数&#xff0c;平常实操的时候也没有遇到过问题&#xff0c;但是今天测试的时候&#xff0c;刚好一…

synchronized的实现原理与应用

在多线程并发中synchronized一直存在&#xff0c;很多人把它称为重量级锁&#xff0c;但随着JavaSE1.6对sycnhronized进行了各种优化后&#xff0c;有些情况就不再那么重了。 接下来详解一下JavaSE 1.6为了减少获得锁和释放锁带来的性能消耗并引入了偏向锁和轻量级锁&#xff…

下载和安装AD14 - Altium Designer 14.3.20.54863

这个版本应该还支持XP 系统[doge]&#xff0c;总之就是想安装一下&#xff0c;没什么特别的意义。 下载 资源来自毛子网站&#xff1a;https://rutracker.net/forum/viewtopic.php?t5140739&#xff0c;带上个网页翻译插件就行。要用磁力链接下载&#xff0c;推荐用qbittorr…

面试算法78:合并排序链表

题目 输入k个排序的链表&#xff0c;请将它们合并成一个排序的链表。 分析&#xff1a;利用最小堆选取值最小的节点 用k个指针分别指向这k个链表的头节点&#xff0c;每次从这k个节点中选取值最小的节点。然后将指向值最小的节点的指针向后移动一步&#xff0c;再比较k个指…

计算机视觉 - 了解Mosaic数据增强

一、简述 数据增强包含各种扩展和增强机器学习和深度学习模型数据集的技术。这些方法跨越不同的类别,每种方法都会改变数据以引入多样性并提高模型的稳健性。几何变换(例如旋转、平移、缩放和翻转)会修改图像方向和结构。颜色和对比度调整会改变图像外观,包括亮度、对比度和…

第八周:AIPM面试准备

以下为从开始准备转行到拿到offer期间每天需要准备的10个面试题目以及相关知识补充&#xff01;来源广泛&#xff0c;从各个地方收集&#xff0c;只提供题目&#xff0c;我自己的尝试回答也会陆续放在我的喜马拉雅&#xff0c;基于我粗浅的认知&#xff0c;分享我粗浅的作答思路…

策略模式(及案例)

策略模式 1.策略接口 定义一组算法或操作的通用接口&#xff0c;通常是一个抽象类或接口。该接口声明了策略类所必须实现的方法。 示例&#xff1a; class Strategy {doOperation() {} }2.具体策略 实现策略接口&#xff0c;提供具体的算法实现。每个具体策略类负责处理一…