前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >重温斐波那契数列,再看时间复杂度的重要性

重温斐波那契数列,再看时间复杂度的重要性

作者头像
有态度的马甲
发布于 2023-09-05 10:47:26
发布于 2023-09-05 10:47:26
28900
代码可运行
举报
文章被收录于专栏:精益码农精益码农
运行总次数:0
代码可运行
  • • 开题引入斐波那契
    • • 代码演示:递归、循环
  • • 递归 vs 循环
    • • 时间复杂复高,指数型O(2^n);推导过程
    • • 占用线程堆栈, 可能导致栈满异常
  • • 压测演示 ​

打入门软件开发,斐波那契数列便是绕不过去的简单编程算法。

一个老生常谈的思路是递归,另外是循环,今天借此机会回顾并演示时间复杂度在编程中的重要性。

斐波那契 递归算法 1,1,2,3,5,8,13,21,34,55

递归算法的应用场景是:

  • • 将大规模问题,拆解成几个小规模的同样问题
  • • 拆解具备终止场景
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Fibonacci(n int) (r int) {
    if n == 1 || n == 2 {
        r = 1
        return
    } else {
        return Fibonacci(n-1) + Fibonacci(n-2)
    }
}

为什么能想到循环, 斐波那契数组也有循环的含义: 第n个数字是循环指针i从第1个数字移动到第n-2个数字时, 第n-2个数字pre和第n-1个数字next的和。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Fibonacci2(n int) (r int) {
   if n==1 || n==2  {
     return 1
   }
   pre,next int :=1,1
   for i:=0; i<=n-1-2; i++ {
       tmp:= pre+next
       pre = next
       next = tmp
   }
}

单元测试如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func TestFibonacci(t *testing.T) {
    t.Logf("Fibonacci(1) = %d, Fibonacci2(1)= %d ", Fibonacci(1), Fibonacci2(1))
    t.Logf("Fibonacci(3) = %d, Fibonacci2(3)= %d ", Fibonacci(3), Fibonacci2(3))
    t.Logf("Fibonacci(8) = %d, Fibonacci2(8)= %d ", Fibonacci(8), Fibonacci2(8))
}

go test ./ -v
=== RUN   TestFibonacci
    m_test.go:8: Fibonacci(1) = 1, Fibonacci2(1)= 1 
    m_test.go:9: Fibonacci(3) = 2, Fibonacci2(3)= 2 
    m_test.go:10: Fibonacci(8) = 21, Fibonacci2(8)= 21 
--- PASS: TestFibonacci (0.00s)
PASS
ok      example.github.com/test 3.359s

递归的问题在于:

(1) 函数调用存在压栈过程,会在线程栈(一般2M)上留下栈帧,斐波那契递归算法:是函数自己调用自己,在终止条件后栈帧开始收敛,但是在此之前有可能已经撑爆线程栈。

栈帧中维持着函数调用所需要的各种信息,包括函数的入参、函数的局部变量、函数执行完成后下一步要执行的指令地址、寄存器信息等。

(2) 斐波那契递归调用存在重复计算,时间复杂度是O(2^n),随着n的增加,需要计算的次数陡然增大(业内称为指数型变化)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 f(n) = f(n-1)+f(n-2)                 // 1次计算
      = f(n-2)+f(n-3)+f(n-3)+f(n-4)   // 3次计算
      = f(n-3)+f(n-4)+f(n-4)+f(n-5)+f(n-4)+f(n-5)+f(n-5)+f(n-6)     // 7次计算                          // 7次计算
      =......
      = f(1)+......                   //  2^n-1次计算
      
 故为斐波那契递归时间复杂度为 O(2^n)     

而我们的循环算法不存在以上问题, 第n个数字需要n -2次计算, 时间复杂度是O(n)

有些童鞋可能没意识到指数型的威力,举个例子, 斐波那契递归算法,第20个数字需要2^20次运算;循环算法只要18次运算。

使用基准测试压测:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func BenchmarkF1(b *testing.B) {
    for i := 1; i < b.N; i++ {
        Fibonacci(20) //  时间复杂度  O(2^n)
    }
}

func BenchmarkF2(b *testing.B) {
    for i := 1; i < b.N; i++ {
        Fibonacci2(20) // 时间复杂度 O(n)
    }
}


go test  -bench=.  -benchmem  ./
goos: darwin
goarch: amd64
pkg: example.github.com/test
cpu: Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
BenchmarkF1-8              55039             20740 ns/op               0 B/op          0 allocs/op
BenchmarkF2-8           196663548                6.080 ns/op           0 B/op          0 allocs/op
PASS
ok      example.github.com/test 3.744s

单次执行效率(ns/op指标)相形见绌,甚至斐波那契递归n>50+ 不一定能计算出来。


ok, that'all. 本次快速记录了递归算法相比循环的两点劣势,这里面很重要的常见时间复杂度变化曲线[1], 需要程序员必知必会。https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/

全文原创,见字如面,若有不同见解或发散思维,文末可留言或直接微信喷我。

引用链接

[1] 常见时间复杂度变化曲线: https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/

自古以来,同步/异步都是八股文第一章

自古以来,反射也是兵家必争之地

Go编程快闪之logrus日志库

流量调度、微服务可寻址性和注册中心

摸鱼快报:golang net/http中的雕虫小技

Go语言正/反向代理的姿势

两将军问题和TCP三次握手

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 精益码农 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
LeetCode题解—斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
码上积木
2021/02/08
1.1K0
斐波那契数列递归算法和非递归算法
斐波那契数列的表达式: F(1)=1 F(2)=1 F(n)=F(n-1)+F(n-2)    (n>2) 递归算法:时间复杂度O(2^n) int recursive_method(int n) { if (n == 1 || n == 2) return 1; else return recursive_method(n - 1) + recursive_method(n - 2); } 非递归算法:时间复杂度O(n) int non
week
2018/08/24
6220
动态规划在斐波那契数列中的应用与优化
斐波那契数列是数学领域中一个经典的问题,在计算机科学中也有广泛的应用。从简单的递归算法到优化的动态规划方法,斐波那契数列的求解体现了算法设计和性能优化的精髓。本文将以动态规划为核心,系统地探讨如何高效地计算斐波那契数列,分析不同方法的时间与空间复杂度,并展示动态规划的强大之处。希望通过本研究,为算法设计爱好者提供启发,并在实际问题中应用该技术。
suye
2024/12/20
1600
斐波那契数列_07
sum 存储第 n 项的值 one 存储第 n-1 项的值 two 存储第 n-2 项的值
名字是乱打的
2021/12/23
1840
斐波那契数列_07
【数据结构】时间复杂度与空间复杂度
数据结构是什么呢?其实数据结构就是计算机存储和组织数据的一种形式,这些数据存在一种或多种特定关系的数据元素的集合。 算法又是什么?数值分析中我们对一个复杂的数学问题,会通过设定特定的算法将这个复杂的数学问题转化成加减乘除进行计算,这也是算法,事实上,算法就是定义良好的计算过程,用来将输入的数据转化成输出结果。
HABuo
2024/11/19
660
【数据结构】时间复杂度与空间复杂度
算法:斐波那契数列 Fibonacci
2 是上两项的和(1+1) 3 是上两项的和(1+2)、 5 是(2+3)、 依此类推!
用户3578099
2022/06/10
4870
算法:斐波那契数列 Fibonacci
【初阶数据结构】时间复杂度和空间复杂度(超有趣+超详细)
作为一位程序员,一颗强有力的好胜心和对知识充满渴望的眼神是必不可少的。如果你还拥有一头秀发,那更是程序员界中的佼佼者(开玩笑)😊。
埋头编程
2024/10/16
1420
斐波那契数列
斐波那契数列的核心就是F(N) = F(N-1) + F(N-2),一般看到的都会采用递归,但是如果使用循环来实现且进行对比,容易发现不少对真是性能的影响
忧愁的chafry
2022/10/30
4720
斐波那契数列
斐波那契数列
斐波那契数列,1,1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 , 89, 144,. 如果设F(n)为该数列的第n 项( n ∈N* ),那么数列有如下形式,F(n)=F(n-1)+F(n 2)。
砖业洋__
2023/05/06
2440
【算法与数据结构】复杂度深度解析(超详解)
算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
学习起来吧
2024/02/29
2500
【算法与数据结构】复杂度深度解析(超详解)
【Java】如何高效计算斐波那契数列:递归与循环的比较与优化
斐波那契数列(Fibonacci Sequence)由意大利数学家列昂纳多·斐波那契在《算术书》中提出,其定义为:数列中的每个数字等于前两个数字之和,通常数列的前两项定义为 1。数列的前几项如下:
CSDN-Z
2025/02/25
1360
【Java】如何高效计算斐波那契数列:递归与循环的比较与优化
斐波那契数列
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
木子星兮
2020/07/17
7290
【C语言入门数据结构】时间复杂度和空间复杂度
数据结构指的是“一组数据的存储结构”,算法指的是“操作数据的一组方法”。 数据结构是为算法服务的,算法是要作用在特定的数据结构上的。
阿伟@t
2023/10/10
3240
【C语言入门数据结构】时间复杂度和空间复杂度
【初探数据结构】时间复杂度和空间复杂度
算法执行时间随输入规模(N)增长的渐进趋势的数学函数,具体表现为算法中基本操作的执行次数。
我想吃余
2025/03/31
1300
【初探数据结构】时间复杂度和空间复杂度
斐波那契数列
刷抖音突然刷到了斐波那契数列,突发奇想就用java写一个斐波那契数列。虽然很早之前学习算法,这应该是最基本的,但是对于一个干着普普通通工作的我已经是需要深思熟虑一番。
cultureSun
2023/09/02
2790
算法 | 详解斐波那契数列问题
上一篇讲到了等比数列求和问题,求S_n = 1 + 2 + 2^2 + 2^3 + ... + 2^{63}= ?,该函数属于爆炸增量函数,如果采用常规运算,则要考虑算法的时间复杂度。
甜点cc
2022/11/02
4890
算法 | 详解斐波那契数列问题
青蛙跳台阶问题暨斐波那契数列
一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法。
恋喵大鲤鱼
2018/08/03
1.1K0
青蛙跳台阶问题暨斐波那契数列
斐波那契数列的四种实现算法
斐波那契数列(Fibonacci Sequence)是一组自然数序列,其特点是每个数都是前两个数之和。斐波那契数列的起始数字通常为0和1,序列依次为0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...。
人不走空
2024/03/23
2560
斐波那契数列的四种实现算法
数学的算法代码如何实现:神奇的斐波那契数列(Fibonacci sequence)
这里推荐一篇实用的文章:《【Docker项目实战】使用Docker部署Notepad轻量级记事本》,作者:【江湖有缘】。
Lion Long
2024/11/16
1310
数学的算法代码如何实现:神奇的斐波那契数列(Fibonacci sequence)
数据结构学习笔记 | 斐波那契数列的两种解法
这个数列是意大利数学家斐波那契在《算盘书》里提出的,在数学上是用递归的方式来定义的:
有财君
2023/06/13
4460
数据结构学习笔记 | 斐波那契数列的两种解法
相关推荐
LeetCode题解—斐波那契数列
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档