算法:斐波那契数列
斐波那契数列
斐波那契数列(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*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
根据推导公式有以下几种实现方式
方式一:普通递归实现:
- 简单易理解
- 时间复杂度:O(n2)
- 空间复杂度:T(n2)
- n稍微大点几乎算不出结果
- 特别提示 如果不想卷铺盖走人,不要写这样的代码
public static int funF(int n) {
if(n<=2) {
return 1;
}
//强两个数相加
return funF(n-1)+funF(n-2);
}
方式二:缓存递归实现
说明:针对上一种实现添加缓存机制,使得一次递归到底之后的数据被缓存,回溯之后数据直接从缓存中取数,不用再次递归。
- 典型的空间换区时间案例(特别注意,这里的空间复杂度相对于简单的递归并没有增加)
- 空间复杂度:T(n)
- 时间复杂度:O(n)
public static int funF(int n,int[] data) {
if( n <= 2 ) {
return 1;
}
//第一次直接忽略,下次进来直接从缓存中取
if( data[n] > 0 ) {
return data[n];
}
data[n] = funF(n-1,data)+funF(n-2,data);
return data[n];
}
方式三:尾递归实现
说明: 此种方法有点难以理解
这种实现的的核心思想就是相对于正常递归倒着计算
例如f(5)计算流程
输入 ==> 输出
第一个参数表示n
第二个参数表示pre
第三个参数表示res
5 1 1 ==> 4 1 2 计算 res = 1+1
4 1 2 ==> 3 2 3 计算 res = 1+2
3 2 3 ==> 2 3 5 计算 res = 2+3
2 3 5 ==> 5 遇到终止条件 5
- 取消了回溯流程,性能大幅度提升
- 空间复杂度:T(n)
- 时间复杂度:O(n)
/**
* 斐波那契数列
* f(n) = f(n-1) + f(n-2)
* 1 1 2 3 5 8
* @param n 第n个数
* @param pre 前一次结果
* @param res 终止条件结果
* @return
*/
public static int funF(int n,int pre,int res) {
if(n<=2) {
return res;
}
return funF(n-1,res,pre+res);
}