定义

斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用。

实现

斐波那契数列是一种广泛应用且规律简单的线性递推数列,在学习的过程中我们常常使用递推方程的方式进行计算。其递推定义如下

F(1)=1,

F(2)=1,

F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)

本文中给出如下函数接口

/*** @param n*           fibonacci数列某一项数* @return *           fibonacci数列第n项的值*/
public int Fibonacci(int n) {}

本文只讨论核心的代码,对于n的合法性判断,返回值是否溢出等问题不进行考虑。但为了保证代码的健壮性希望各位读者继续对以下实现代码进行更详细的完善。

思路一:递归

使用递归解决该问题十分简单明了,其实现如下。

public int Fibonacci(int n) {if (n == 1 || n == 2)return 1;return Fibonacci(n - 1) + Fibonacci(n - 2);
}

递归这种方式十分简单,容易理解。但缺点是开销大、容易产生栈溢出。通过归纳法可以证明其渐进时间复杂度为O((5/3)^N),也即指数级,这是一种对递归十分低效的应用,其辅助空间复杂度为O(n)。另外需要注意的是这里的代码对n并未进行合法性判断,如果输入为负数将会出现栈溢出。

思路二:迭代

迭代算法也是基于递推方程实现,通过不断的迭代,去求解新的项。其迭代关系式如下:

X = F(0) = 0,

Y = F(1) = 1,

Y = F(1) + F(0) = F(2) ,

X = Y - X = F(2) - F(0) = F(1)

... ...

基于以上关系式,给出实现代码。

public int Fibonacci(int n) {int x = 0, y = 1;for (int i = 1; i <= n; i++) {y = x + y;x = y - x;}return x;
}

迭代思路求斐波那契数列第n项时间复杂度为O(n),辅助空间复杂度为O(1)。相比递归方式,更推荐使用迭代求解斐波那契问题。相比递归其唯一的缺点可能就是可读性没有递归方式高。

思路三:数组

以上两种思路是学习中较为常见的求解斐波那契数列第n项的方式,但如果问题变化,变成求解斐波那契数列前n项,继续使用以上思路的时间复杂度就会变为O(N(5/3)^N)和O(N^2),这是相对复杂的。所以在斐波那契数列前n项时,推荐利用数组来解决问题。其实现代码如下。

public int[] Fibonacci(int n) {int fib[] = new int[n+1];fib[0] = 0;fib[1] = 1;for (int i = 2; i <= n; i++) {fib[i] = fib[i - 1] + fib[i - 2];}return fib;
}

数组实现类似于前文的递归实现,利用前两项元素之和去求解第三项。所以时间复杂度是O(n)。这种方式的优点在于,每一项的生成都依赖于数组中现有的项,所以如果得到了第n项,也就得到了前n-1项。产生的所有的中间结果都保存在数组之中,如果使用上文的迭代方式求解斐波那契数列前n项,每次生成新项都需要从F(1)开始重新进行迭代,效率较低。

还需要注意的是,由于使用了int类型的数组,所以n的值最大只能为46,因为F(46) = 1836311903。再向上进行迭代就会造成int类型溢出。对于这个问题可以采用long或者BigInteger去解决。

思路四:通项公式

由于斐波那契数列是一个线性递推数列,所以可以使用多种方法(特征方程、待定系数、blabla...)去推导,最终得到的通项公式如下:

代码实现如下。

public int Fibonacci(int n) {final double SQRT_FIVE = Math.sqrt(5);double result = 1 / SQRT_FIVE * (Math.pow((1 + SQRT_FIVE) / 2, n) - Math.pow((1 - SQRT_FIVE) / 2, n));return (int) result;
}

对于求解斐波那契数列某一项而言,这种方式的渐进时间复杂度最低——O(1),因为是利用公式。然鹅如果不无视pow的开销的话,复杂度大概是O(logN),因为Java的Math.pow()底层其实是一个native方法StrictMath.pow(),调用了C++中的pow函数,其渐进时间复杂度为O(logN)。

其实现思路算法大致如下:

public double pow(double x, int y){  if (y == 0) return 1; if (y == 1) return x;  double result = 0;  double tmp = pow(x, y/2);  if(y & 1 != 0){  //判断奇偶result = x * tmp * tmp;  } else{  result = tmp * tmp;  }  return result;
}  

熟悉的同学应该能看出来这就是快速幂的一种实现哈哈哈~~~

以上是笔者关于解决斐波那契数列问题的几种思路,代码还有许多不完善的地方,如有缺漏,欢迎大家指正。

斐波那契数列(Fibonacci sequence)【思路及实现】相关推荐

  1. matlab 斐波那契数列Fibonacci Sequence

    斐波那契数列Fibonacci Sequence 主代码 %% 清理可能存在的旧数据 clc; % 清屏 clear; % 清除变量 close; % 关闭可能存在的窗口 %% 调用主要代码 n = ...

  2. 求解斐波那契数列(Fibonacci Numbers)算法居然有9种,你知道哪几种吗?

    By LongLuo 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为&q ...

  3. 斐波那契数列 (Fibonacci) 多种实现方法(Python)与详细介绍

    斐波那契数列 Fibonacci Sequence 本文介绍了多种方式得到斐波那契数列或斐波那契数.斐波那契数列也称为"兔子数列".来源于兔子繁殖的预测.它的重要性体现在相邻两数之 ...

  4. 斐波那契数列(Fibonacci) - 这就是算法吗?爱了爱了

    斐波那契数列(Fibonacci) 今天开始做牛客的剑指Offie,一看到斐波那契我就想到递归,是它是它就是它,然后我就满怀期待地写下了下面地代码.ok,没问题,一次性过.然而,我滴老天鹅,才击败30 ...

  5. JavaScript实现以数组形式返回斐波那契数列fibonacci算法(附完整源码)

    JavaScript实现以数组形式返回斐波那契数列fibonacci算法(附完整源码) fibonacci.js完整源代码 fibonacci.js完整源代码 export default funct ...

  6. Java数据结构与算法---斐波那契数列Fibonacci

    Java数据结构与算法-斐波那契数列Fibonacci 原理都很简单,直接上代码: package cn.m_fibonacci;public class Fibonacci {public stat ...

  7. JAVA编程:斐波那契数列(Fibonacci)

    JAVA编程09:斐波那契数列(Fibonacci),输入一个数据n,计算[斐波那契数]列(Fibonacci)的第n个值 需调用run9方法 /*输入一个数据n,计算[斐波那契数]列(Fibonac ...

  8. Java实现斐波那契数列Fibonacci

    import java.util.Scanner; public class Fibonacci {public static void main(String[] args) {// TODO Au ...

  9. 斐波拉契数列(简单思路)

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

  10. python利用递归函数实现斐波那契数列_Python使用while循环输出斐波那契数列(Fibonacci)...

    斐波那契数列又称费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列.在西方,首先研究这个数列的是比萨的列奥那多(意大利人 ...

最新文章

  1. 新年新技术:MongoDB 3.0
  2. 清理svn信息_推荐候选人有奖啦~11.26最新招聘信息看这里!
  3. 面试官:为什么mysql不建议执行超过3表以上的多表关联查询?
  4. 2019 .NET China Conf:路一直都在,社区会更好
  5. 联合概率,条件概率,边缘概率的通俗理解
  6. 杭电1434 幸福列车
  7. 我眼中未来的人机交互
  8. 使用python对文件下的文件批量重命名
  9. CentOS的SSH,Putty配置说明
  10. axure轮播图怎么设置循环轮播_Axure RP8 动态面板之轮播图设置
  11. 关于高德百度地图坐标系问题
  12. 紫外分光光度法测量蛋白质的含量
  13. Android 控制音频的音量大小
  14. OFFICE2016用过一段时间后正版密钥显示未激活问题
  15. win10系统qq截图时屏幕局部自动放大怎么办 解决方法
  16. MQTT:Massage Queue Telemetry Transport消息队列遥测传输
  17. 大学计算机基础线下作业,【计算机基础论文】大学计算机基础教学新形式探究(共4665字)...
  18. 数据分析之Matplotlib(二)折线图(plot)
  19. 自我保健很重要:先付钱
  20. 核糖体rRNA分类-功能应用-数据库-Silva

热门文章

  1. 浅析分布式系统之体系结构 - 事务与隔离级别(多对象、多操作)上篇
  2. 2024年浙大MBA提前批面试申请“四步曲”,凡事预则立,不预则废
  3. 贷款那些事之还款方式平息法(五)
  4. excel中设置下拉选择框和word文档中插入外部excel只显示图标
  5. 想看Dubbo源码?建议先看看这一篇
  6. 数据库字段类型、JDBC类型、Java类型映射关系
  7. 【Vue教程三】点击事件、表单输入事件、键盘事件
  8. 【作品】Web刷人气の工具
  9. Python数据清洗分列函数,解决多字段数据分列的串行问题
  10. lv编码vi0055_LV包包内部编号问题