定义

斐波那契数列(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. 文件解析库doctotext源码分析
  2. 网络访问:本地账号的共享和安全模式设置身份验证后自动更改其他验证的处理方法 ...
  3. oracle1537,dataguard 出现ORA-16136错误
  4. c++类中成员的构造顺序
  5. Hadoop学习笔记03_Hive练习
  6. python学习笔记(五)
  7. 算法:两个数的和等于指定值1. Two Sum
  8. 取数工具服务器文件夹,财务软件取数工具
  9. Appium环境搭建教程
  10. unity 自定义管线SRP 学习笔记(一)搞懂WHY WHAT HOW
  11. 什么是后端开发?后端能做什么?全栈工程师又是什么?
  12. AutoSAR入门到精通讲解 (AuroSAR-CP描述) 1.1 AutoSAR-CP简介
  13. antv g2字体阴影_antv g2 notes
  14. Ubuntu 20.04安装velodyne_simulator
  15. 汽车车灯注塑件三维尺寸公差检测
  16. Linux通过vidpid找到摄像头对应的索引
  17. 11个你可能不知道的Python库
  18. miRNA数据库篇——miRDB:软件预测的哺乳动物miRNA靶基因数据库(假阳性较高)
  19. 【educoder】头歌 数据结构与算法 答案
  20. 精诚探索,极客归来!百度安全打造全球首个元宇宙安全极客大会,共筑 AI 安全新防线...

热门文章

  1. 解决 Win10 热点无法上网及与 Hyper-V 虚拟网卡冲突问题
  2. android app安装出现 xxx存在内容提供者冲突无法安装
  3. Java实体类字段类型与MySQL数据库字段类型的对应关系
  4. 34 | 别再说不能使用Join了(这是常识问题-上篇)
  5. 华为交换机telnet配置方法
  6. 非root账号安装nginx1.22.0
  7. 缓存详解-在java项目中使用缓存
  8. C++ 函数模板的使用
  9. 华为手表新款watch gt3_华为发布会内容前瞻,除了mate40系列,还有3款新品出现!...
  10. python学习环境安装