斐波那契数列想必大家都听过,如果感觉斐波那契数列有点陌生的同学,肯定是没有好好学算法。一般在讲解递归的时候,我们都会拿出斐波那契数列这个例子来,因为它实在太经典了,今天我们就来深入研究一下斐波那契数列的解法。

什么是斐波那契数列?

数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。他当时是这样提出的:假设一对刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,一年内没有发生死亡,问:一对刚出生的兔子,一年内繁殖成多少对兔子?

形成数列就是:0、1、1、2、3、5、8、13、21、34、……

在数学上,斐波那契数列以如下被以递推的方法定义:F( 0 )=0,F( 1 )=1, F( n )=F( n - 1 ) + F( n - 2 )(n≥ 2,n ∈ N*)

解法一:递归

时间复杂度:O(2ⁿ)

空间复杂度:O(1)

斐波那契数列就是为递归而生的,我们从题中就可以找到它的规律就是后一个数是前两个数之和,它的边界就是F( 0 )=0,F( 1 )=1,它的递归调用就是 F( n - 1 ) + F( n - 2 ) 。

原理图:

代码如下:

public int fibonacci(int n) {if (n < 2) {return n;}return fibonacci(n-1) + fibonacci(n-2);
}
复制代码

解法二:记忆化搜索(备忘录算法)

时间复杂度:O(n)

空间复杂度:O(n)

通过上边递归的原理图片可以看出,递归时大量的中间数据是存在重复计算的,我们将这些重复的中间值通过Map缓存起来,这样同样的值我们只需要递归计算一次,就能得到解,能够极大的提高递归的效率,这就是记忆化搜索。

此种算法,是典型的用空间换时间,有n个数我们就需要缓存n个值。

优化后我们需要的计算量,是不是大幅提升呢,从下图就可以得到答案

代码如下:

public int fibonacci(int n, Map<Integer,Integer> cache) {if (n < 2) {return n;}if (cache.containsKey(n)) {return cache.get(n);}int value = fibonacci(n - 1, cache) + fibonacci(n - 2, cache);cache.put(n,value);return value;
}
复制代码

解法三:动态规划

时间复杂度:O(n)

空间复杂度:O(1)

递归是一种自顶向下求解的过程,那么我们能不能自低向上求解呢?

自低向上就是说我们由F( 0 )=0,F( 1 )=1,F( 2 )...F( n )这样是不是更好呢?很显然可以的。

正是由于斐波那契数存在这种递推关系,所以我们可以使用动态规划求解。动态规划的状态转移方程即为上述递推关系,边界条件为 F(0) 和 F(1)。

根据动态规划的状态转移方程和边界条件,我们可以得到时间复杂度和空间复杂度都是 O(n) 的实现。由于 F(n) 只和 F(n−1) 与 F(n−2) 有关,因此可以使用 【滚动数组思想】 把空间复杂度优化成 O(1)。

代码如下:

public int fibonacci(int n) {if (n < 2) {return n;}int p = 0, q = 0, r = 1;for (int i = 2; i <= n; ++i) {p = q; q = r; r = p + q;}return r;}
}
复制代码

解法四:矩阵快速幂

时间复杂度:O(logn)

空间复杂度:O(1)

动态规划的时间复杂度是 O(n)。我们可以使用矩阵快速幂的方法来降低时间复杂度。

首先构建递推关系:

得到

public int fibonacci(int n) {if (n < 2) {return n;}int[][] q = {{1, 1}, {1, 0}};int[][] res = pow(q, n - 1);return res[0][0];
}
​
public int[][] pow(int[][] a, int n) {int[][] ret = {{1, 0}, {0, 1}};while (n > 0) {if ((n & 1) == 1) {ret = multiply(ret, a);}n >>= 1;a = multiply(a, a);}return ret;
}
​
public int[][] multiply(int[][] a, int[][] b) {int[][] c = new int[2][2];for (int i = 0; i < 2; i++) {for (int j = 0; j < 2; j++) {c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];}}return c;
}
复制代码

解法五:通项公式

斐波那契数 F(n) 是齐次线性递推,根据递推方程 F(n)=F(n-1)+F(n-2),

可以写出这样的特征方程:x²=x+1

代码中pow 函数的时间、空间复杂度与 CPU 支持的指令集相关,这里不深入分析。

代码如下:

public int fibonacci(int n) {double sqrt5 = Math.sqrt(5);double fibN = Math.pow((1 + sqrt5) / 2, n) - Math.pow((1 - sqrt5) / 2, n);return (int) Math.round(fibN / sqrt5);
}
复制代码

说明:

解法四,解法五是在LeetCode题解中上发现的,效率是真的高,但我看的也是模棱两可,这些都是高等数学的相关知识点,感兴趣的可以深入研究一下,算法的尽头还是数学啊!!!

前三个解法是我们每个人都应该掌握的。

花式破解斐波那契数列相关推荐

  1. 采用数组实现斐波那契数列的计算、foreach循环的使用、100以内质数的判断

    想要实现斐波那契数列的计算,我们首先得了解斐波那契数列的定义及其原理: 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契以兔子繁殖为例子而引入,故又称 ...

  2. 兔子繁衍问题-暴力破解+斐波那契

    解法1.我是用暴力破解,循环解决 #include<iostream> using namespace std; /*一对兔子,从出生后第3个月起每个月都生一对兔子. 小兔子长到第3个月后 ...

  3. java 斐波拉_Java实现斐波那契数列

    斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n&g ...

  4. 剑指offer:面试题10- I. 斐波那契数列

    写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项.斐波那契数列的定义如下: F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 ...

  5. 用递归法计算斐波那契数列的第n项

     斐波纳契数列(Fibonacci Sequence)又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1, ...

  6. 循环斐波那契数列_剑指offer #10 斐波那契数列

    (递归和循环)#10 斐波那契数列 一.斐波那契数列 定义: n = 0 , f(n) = 0 n = 1 , f(n) = 1 n > 1 , f(n) = f(n-1) + f(n-2) 思 ...

  7. 用C语言编写:判断一个≥2的整型数是否存在于斐波那契数列中?

    自己写的,感觉挺有成就感的,就展示出来吧! 判断一个≥2的整型数是否存在于斐波那契数列中? 若存在,则返回第几项:若不在,则返回-1 #include <stdio.h> long gen ...

  8. 算法(1)斐波那契数列

    1.0 问题描述 实现斐波那契数列,求第N项的值 2.0 问题分析 斐波那契数列最简单的方法是使用递归,递归和查表法同时使用,可以降低复杂度. 根据数列特点,同时进行计算的数值其实只有3个,所以可以使 ...

  9. NOIP模拟题 斐波那契数列

    题目大意 给定长度为$n$序列$A$,将它划分成尽可能少的若干部分,使得任意部分内两两之和均不为斐波那契数列中的某一项. 题解 不难发现$2\times 10^9$之内的斐波那契数不超过$50$个 先 ...

最新文章

  1. 使用Docsify搭建Markdown文件服务器
  2. 扑克牌图片一张一张_Python 制作一副扑克牌,有趣的案例
  3. python控制手机自动刷新闻_python +adb控制手机自动化签到
  4. 日期/时间格式/解析,Java 8样式
  5. Pytorch LSTM初识(详解LSTM+torch.nn.LSTM()实现)1
  6. Matlab语音采集与读写程序,基于MATLAB的语音信号录制采集和分析的程序设计
  7. mycat两个mysql实例的搭建_Mycat-多实例的搭建
  8. python数值运算操作符也叫做内置操作符_Python的操作符 - osc_r1gtal48的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. (洛谷)P2709 小B的询问
  10. 从医生看病和快餐店点餐理解Node.js的事件驱动
  11. android禁止锁屏保持常亮
  12. Atitit 微服务实践 艾提拉著 微服务主要解决几个问题负载均很 目录 1. 微服务的模式 http请求层 vs服务层 1 1.1. Http vs 服务层优缺点 1 2. 实现技术 2
  13. (转)美国国家科学院院士张首晟演讲全文:人工智能的三大发展支柱
  14. Bing API 将新增 Bing 空间数据服务
  15. web前端开发师前景,96道前端面试题
  16. 如何把视频转换成mp3格式
  17. 天蓝色在ps中的色值_天蓝色事件网格集成测试
  18. NGUI学习笔记(四).Sprite的Sliced类型与解决拉伸模糊的问题
  19. 美团机器学习InAction系列—实例详解机器学习如何解决问题
  20. PageAdmin CMS仿站教程,自己建网站就是如此简单

热门文章

  1. 嵌入式硬件基础之SPI总线详解
  2. 粗暴解决node-gyp的configure error问题
  3. B树与B+树的区别!!
  4. 照片变年轻特效怎么做?看看年轻的自己这样操作
  5. 前所未有的详细总结 BLAS (零)
  6. 转:如何提高网页的效率(下篇)——Use YSlow to know why your web Slow
  7. 自然语言处理(NLP)入门
  8. vnc与windows之间的复制粘贴
  9. Iphone开发基础教程 (7章 标签栏与选取器)--读书笔记
  10. AI for everyone 笔记