斐波那契数列(递归改进)

2023-11-01

题目:求斐波那契数列的第n项

写一个函数,输入n,求斐波那契数列的第n项。斐波那契数列的定义如下:

大多数人看到后第一时间都会写出如下代码:

递归:方法直观但时间效率低

long long Fibonacci(unsigned int n)
{
  if(n<=0)
    return 0;
  if(n==1)
    return 1;

  return Fibonacci(n-1)+Fibonacci(n-2);
}

 即使很多教科书在讲解递归时都会利用该问题,但并不说明递归的解法最适合这道题目,对于这道题递归存在严重的效率问题。

我们以求解f(10)为例来分析递归求解的过程,用树形结构表示如下图所示:

我们可以发现,在这棵树中有很多节点是重复的,且随着n的增大重复的节点数急剧增加,同时计算量也急剧增大,用递归方法计算的时间复杂度是以n的指数的方式递增的。

改进:

尽量避免重复计算,可以将已经得到的数列中间项保存起来,在下次需要计算的时候先查找一下,如果已经计算过了后面就不再重复计算。

最简单的方法即从下往上计算,用f(0)和f(1)计算f(2),以此类推就可以得到第n项,这种思路的时间复杂度为O(n)。

循环:时间效率提高

long long Fibonacci(unsigned n)
{
  if(n<2)
    return n;

  long long fib1=1;
  long long fib2=0;
  long long fibn=0;
  for(unsigned int i=2;i<=n;i++)
  {
    fibn=fib1+fib2;
    fib2=fib1;
    fib1=fibn;
  }
return fibn;
}

扩展方法:

还存在更快的O(logn)算法,需要用到如下的数学公式:

我们只需要求后面的矩阵就可以得到f(n),现在问题转换为求矩阵的乘方。如果只是简单地从0开始循环,n次方需要n次运算,则其时间复杂度仍然是O(n),并不比前面快。但我们可以考虑乘方的如下性质:

从上面的公式中我们可以看出,若想求得n次方,就要先求得n/2次方,再把n/2次方的结果平方一下即可。可以用递归的思路实现。 

基于矩阵乘法:创意算法,但隐含时间常数较大

#include <cassert>

struct Matrix2By2
{
    Matrix2By2
    (
        long long m00 = 0, 
        long long m01 = 0, 
        long long m10 = 0, 
        long long m11 = 0
    )
    :m_00(m00), m_01(m01), m_10(m10), m_11(m11) 
    {
    }

    long long m_00;
    long long m_01;
    long long m_10;
    long long m_11;
};

Matrix2By2 MatrixMultiply
(
    const Matrix2By2& matrix1, 
    const Matrix2By2& matrix2
)
{
    return Matrix2By2(
        matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
        matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
        matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
        matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
}

Matrix2By2 MatrixPower(unsigned int n)
{
    assert(n > 0);

    Matrix2By2 matrix;
    if(n == 1)
    {
        matrix = Matrix2By2(1, 1, 1, 0);
    }
    else if(n % 2 == 0)
    {
        matrix = MatrixPower(n / 2);
        matrix = MatrixMultiply(matrix, matrix);
    }
    else if(n % 2 == 1)
    {
        matrix = MatrixPower((n - 1) / 2);
        matrix = MatrixMultiply(matrix, matrix);
        matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0));
    }

    return matrix;
}

long long Fibonacci_Solution3(unsigned int n)
{
    int result[2] = {0, 1};
    if(n < 2)
        return result[n];

    Matrix2By2 PowerNMinus2 = MatrixPower(n - 1);
    return PowerNMinus2.m_00;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

斐波那契数列(递归改进) 的相关文章

  • std::vector 的复制构造函数如何运行?

    一个如何std vector
  • OpenGL纹理渲染与原始不匹配

    我正在尝试使用 OpenGL 渲染纹理 我用作测试的纹理是白色背景上的一堆黑色矩形 如下所示 然而 在渲染时 纹理似乎被复制并叠加在其自身之上多次 我使用以下方法设置场景 std string vertexSource ShaderLoad
  • 使用 QTextCursor 选择一段文本

    使用 Qt 框架选择文本片段时遇到问题 例如 如果我有这个文件 没有时间休息 我想选择 ime for r 并从文档中删除这段文本 我应该如何使用 QTextCursor 来做到这一点 这是我的代码 QTextCursor cursor n
  • 无法在更新面板中找到上传的文件

    aspx
  • 错误 C2064:术语不计算为采用 1 个参数的函数

    class Student bool Graduate return m bGraduate class School vector
  • 优化对绑定到 DataGridView 的 DataTable 的更新

    我的应用程序中有一个显示一些数据的表单 当我第一次显示表单时 我将一些数据加载到 DataTable 中 然后将 DataTable 绑定到 DataGridView 我还启动了一个异步方法来执行一些较慢的数据库查询 当这些慢查询完成时 我
  • 使用 boost::iterator_facade<>

    我有一个链表结构 struct SomeLinkedList const char bar int lots of interesting stuff in here DWORD foo SomeLinkedList pNext 它是现有
  • ResourceDictionary 源中的 Uri 语法(通用 Windows 平台)

    我正在迁移我的Windows 8 1项目到Windows 10 通用 Windows 平台 这时我被拦住了ResourceDictionary改变在UWP 为了简单起见 我有包含 2 个项目的 Windows 8 1 解决方案 App pr
  • F# 内联如何工作?

    对于 F 我的理解是您可以使用 inline 关键字在调用站点执行类型专门化 那是 val inline a gt b gt c when a or b static member a b gt c 约束条件是 a or b必须有一个静态成
  • 使用 for 循环创建链表

    这是我的结构 struct ListItem int data struct ListItem next 假设链表的第一个节点的 data 0 我想编写一个 for 循环来创建大小为 5 的链表 但我不知道如何工作 我尝试了以下方法 int
  • 如何忽略搜索条件中的空属性

    我有一个不好的要求要做 无论如何 我必须在我的应用程序中实现它 我有一个Track class public class Track public string Name get set public string City get set
  • 复杂的 C 声明

    我刚刚在互联网上浏览了一些代码 发现了这个 float foo SIZE SIZE 我如何阅读这份声明 是否有一套特定的规则来阅读如此复杂的声明 我有一段时间没做这个了 从 开始foo然后向右走 float foo SIZE SIZE fo
  • 带有 Unicode 字符的主机名在 Windows 8 中有效

    Uri CheckHostName 回报UriHostNameType Unknown到处都是 但在 Windows 8 上 它又回来了UriHostNameType Dns 为什么突然间带有 Unicode 西里尔字符的主机名在 Wind
  • 一个对大文件有效的轻量级 XML 解析器?

    我需要解析潜在的巨大 XML 文件 所以我猜这排除了 DOM 解析器 是否有任何优秀的 C 轻量级 SAX 解析器 在占用空间上可与 TinyXML 相媲美 XML的结构非常简单 不需要诸如命名空间和DTD之类的高级东西 只是元素 属性和
  • 如何从句柄确定进程是 32 位还是 64 位?

    如何从使用 OpenProcess 获取的进程句柄中获取信息 无论进程是 32 位还是 64 位 是的 IsWow64Process 毫无用处 令人烦恼 它的真正意思是 启用了 32 位模拟 如果您在 32 位操作系统上运行 则返回 fal
  • 检测用户是否正在滚动 dataGridView 滚动条

    我正在更新一个dataGridView与一个新的数据表使用 dataGridView1 DataSource table 但是 我不想在用户滚动 dataGridView 时执行此操作 如何检查滚动条是否正在滚动或已完成滚动 即拖动而不是单
  • 序列化时如何跳过 xml 声明?

    我正在尝试输出一个没有 xml 头的 xml 文件 例如 我试过 Type t obj GetType XmlSerializer xs new XmlSerializer t XmlWriter xw XmlWriter Create c
  • RabbitMQ + Windows + LDAP 无需发送密码

    我正在尝试在 Windows 7 上使用 RabbitMQ 3 6 2 进行 LDAP 身份验证 授权 我已经在应用程序发送用户名 密码的情况下进行了基本身份验证 但密码位于我需要弄清楚如何进行的代码中避免 有没有人在不提供密码的情况下成功
  • 即使对于新上下文,OnModelCreating 也仅调用一次

    我有多个相同但内容不同的 SQL Server 表 在编写代码优先 EF6 程序时 我尝试为每个程序重用相同的数据库上下文 并将表名称传递给上下文构造函数 然而 虽然每次都会调用构造函数 但尽管每次都是从 new 创建数据库上下文 但 On
  • 没有运算符“<<”与这些操作数匹配[重复]

    这个问题在这里已经有答案了 不知道发生了什么事 我查看了与此问题类似的其他帖子 但到目前为止没有解决方案有帮助 这是带有错误部分注释的代码 在某一时刻 它说 不起作用 而在代码的其余部分中 它说 include

随机推荐

  • 【C++STL】快速排序算法(sort)的原理与使用

    一 sort算法原理 std sort 是 C 标准库中提供的排序算法 它使用的是一种经典的排序算法 快速排序 Quicksort 或者是其变种 快速排序是一种基于比较的排序算法 通过不断地选择一个基准值 pivot 将待排序序列分割为两个
  • 做好参加蓝桥杯省赛的准备

    1 选择方向 在除此选择要参加蓝桥杯的方向时是刚学完Java程序设计 对Java产生了比较大的兴趣 也觉得Java是一个特别灵活好用的语言 特别是eclipse的强大快捷键和找错功能使得编程快了很多 也有部分原因是因为C 好长时间没用 都快
  • android oaid

    Oaid获取接入流程 移动智能设备标识公共服务平台 AndroidID IMEI OAID获取 oaid sdk 1 1 0的aar 随着Google对隐私的重视以及Android10的逐渐普及 获取设备的唯一标识越来越来难 在Androi
  • python爬取豆瓣电影并分析_爬取豆瓣电影top250提取电影分类进行数据分析

    标签 空格分隔 python爬虫 一 爬取网页 获取需要内容 我们今天要爬取的是豆瓣电影top250 页面如下所示 我们需要的是里面的电影分类 通过查看源代码观察可以分析出我们需要的东西 直接进入主题吧 知道我们需要的内容在哪里了 接下来就
  • echarts实现横向柱图文字在柱图上面

    前言 echarts实现横向柱图文字在柱图上面 效果图 实现源代码 div style width 100 height 800px div
  • Immer编写简洁的更新state逻辑

    react官网推荐库use immer https www npmjs com package use immer 引入 import useImmer from use immer 优点 简化代码 只需要关注需要变动的部分 而 immer
  • python 使用sys.setdefaultencoding(‘utf-8‘) 显示中文(中文默认会乱码)

    正常情况下 我们在使用python做页面开发时 防止中文出现乱码问题 python2 情况下会使用 如下语句 import sys reload sys sys setdefaultencoding utf 8 但在python3下 报错
  • linux安装nodejs_Ubuntu 18.04 Linux上安装Etherpad,基于Web的实时协作编辑器

    介绍 Etherpad是一个开源的 基于Web的实时协作编辑器 它允许多个人使用他们的Web浏览器同时编辑文档 它还提供了一些很酷的功能 如富文本格式和即时消息 目标是在Ubuntu 18 04 Linux上安装Etherpad 约定 要求
  • vmwre15.5.1安装mac遇到的问题以及解决方法和相应工具

    虚拟键15 5 1 mac cdr文件 百度都是 注意版本 破解vmware没有apple操作系统选项 unlock工具 链接 https pan baidu com s 1tE91r3eCG3Swg3FDi VZ8A 提取码 d54g 放
  • ubuntu22安装和卸载nvidia驱动

    一 安装nvidia驱动 查看可以安装的版本 ubuntu drivers devices 选择安装nvidia driver 515 sudo apt install nvidia driver 515 重启 sudo reboot 验证
  • 服务器系统兼容性问题,微软表示因兼容性问题,部分用户无法升到Windows10最新版本...

    微软已警告Windows 10用户 由于英特尔Thunderbolt NVMe SSD的兼容性问题 他们可能被禁止升级到Windows 10版本2004或20H2 每当Microsoft发布新功能更新时 即使是次要功能更新 例如Window
  • SpringBoot3集成Kafka

    标签 Kafka3 Kafka eagle3 一 简介 Kafka是一个开源的分布式事件流平台 常被用于高性能数据管道 流分析 数据集成和关键任务应用 基于Zookeeper协调的处理平台 也是一种消息系统 具有更好的吞吐量 内置分区 复制
  • 【Vue3】vite打包报错:块的大小超过限制,Some chunks are larger than 500kb after minification

    问题描述 vite打包报错 块的大小超过限制 Some chunks are larger than 500kb after minification 解决方法 1 加大限制的大小将500kb改成1000kb或者更大 chunkSizeWa
  • 2022.6.1 C++——类型设计与实例化对象

    对象的创建与使用 对象的创建与使用 1 直接定义类的实例 对象 2 C 对象模型讨论 3 this指针的作用 对象是类的实例 声明一种数据类型只是告诉编译系统该数据类型的构造 并没有预定内存 类只是一个样板 图纸 以此样板可以在内存中开辟出
  • java 使用jdbc向mysql数据库中插入1亿条数据

    http blog csdn net home zhang article details 50836253 java view plain copy
  • 弱网压测环境 - tcconfig

    弱网压测环境 tcconfig 服务器性能指标 服务器接口的容错机制及重连机制需正常 服务器之间的网络通信需正常 服务器存储数据需一致及准确 请求不发生堆积 数据不发生错乱 弱网指标 带宽 吞吐量 单位时间内传输的数据量 单位通常是 每秒比
  • ROSE笔记-ctf.show_web2-WP

    ctf show web2 WP 直接是一个登录界面 在用户名处输入万能密码 admin or 1 1 显示了登陆信息 现在就是去找回显位置 用order by判断当前查询的列数 order by 4的时候登陆信息消失 而order by
  • 根据Modeller官网教程进行单模板建模

    Tutorial Basic Modeling https salilab org modeller tutorial basic html 1 搜索相关序列 从官网下载源文件 分析 TvLDH ali 存放目标序列 需满足要求的格式 gt
  • 异常处理函数set_exception_handler

    由于历史原因 php一开始被设计为一门面向过程的语言 所以异常处理没有使用像Java一样的 try catch 机制 出错时直接显示到页面上 或者记录到web服务器的错误日志中 并且php的错误分成了很多的级别 例如E ERROR E WA
  • 斐波那契数列(递归改进)

    题目 求斐波那契数列的第n项 写一个函数 输入n 求斐波那契数列的第n项 斐波那契数列的定义如下 大多数人看到后第一时间都会写出如下代码 递归 方法直观但时间效率低 long long Fibonacci unsigned int n if