Fibonacci数列学习笔记
无意中在网上看到Fibonacci数列的文章,就又重新学习了一把。
这里是来在维基百科上的关于Fibonacci数列的介绍:
- F0 = 0
- F1 = 1
- Fn = Fn - 1 + Fn - 2
用文字来说,就是斐波那契数列由0和1开始,之后的斐波那契数就由之前的两数相加。首几个斐波那契数是(OEIS A000045):
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,………………
特别指出:0不是第一项,而是第零项。
关于Fibonacci数列的一些神奇的特性:
- Fibonacci数列可以表示为无限连分数。而黄金分割数也是无限连分数。所以Fibonacci数列的后一个数与前一个数的比是趋向于黄金分割比例的。
- 向日葵的种子的螺旋排列99%的符合Fibonacci数列的。
- Fibonacci前n项的和等于F(n+2)-1。
![](https://images.cnblogs.com/cnblogs_com/laynelin/Fibonacci/3422e7fe81c2d7345d6008a7.gif)
如果任意挑两个数为起始,比如5、-2.4,然后两项两项地相加下去,形成5、-2.4、2.6、0.2、2.8、3、5.8、8.8、14.6……等,你将发现随着数列的发展,前后两项之比也越来越逼近黄金分割,且某一项的平方与前后两项之积的差值也交替相差某个值
![](https://images.cnblogs.com/cnblogs_com/laynelin/Fibonacci/9ed6a68b133d4c7a9f2fb4ac.jpg)
![](https://images.cnblogs.com/cnblogs_com/laynelin/Fibonacci/a9a9cd8082d267d29023d9a3.jpg)
![](https://images.cnblogs.com/cnblogs_com/laynelin/Fibonacci/ba1b7bd974f96aec38012fa2.jpg)
面试中关于Fibonacci数列最常见的问题应该就是求第n项的值。在这里列出一些现有的解法:
1、递归
递归应该是最直观的第一时间会被想到的算法。但是用递归来求Fibonacci第n项的值存在严重的性能问题(递归过程中存在大量重复计算,比如算F(5)的时候会算F(3), 算F(6)也会算F(3)......),算法复杂度为O(2^n),差不多当n大于46的时候,运算速度就难以让人忍受。 这里给出基于递归的代码:
{
if (data == 0)
{
return 0;
}
if (data == 1)
{
return 1;
}
else
{
return Fibonacci1Recursive(data - 2) + Fibonacci1Recursive(data - 1);
}
}
2、引入中间变量储存计算结果以进行单层循环
为了解决递归过程中产生的大量重复计算,可以引入中间变量用于保存计算过的结果。这样只需要执行从0到n的循环就可以了,算法负责度为O(n)。以下是范例代码:
{
int data = (int)inputData;
double num1=0, num2=0, num3=0,result=0;
for (int i = 0; i <= data; i++)
{
if (i == 0)
{
num1=0;
result = num1;
}
else if (i== 1)
{
num2 = 1;
result = num2;
}
else
{
num3 = num1 + num2;
num1 = num2;
num2 = num3;
result = num3;
}
}
return result;
}
这样的O(n)的算法在处理相对大一些的数还可以接受,但是在处理一些极大的数时,性能还是不能让人接受。
3、通项公式(初等代数解法)
在面试中,得出这样的结论还不够,面试官还会问有没有效率更高的算法了。一般尝试过直观解法(算法复杂度可能会很高),被一定程度优化的解法(通过一些编程层面的技巧可能能把算法复杂度降到O(N)或O(logN)),还要进一步优化的话,就得上升到数学高度了(初等数学,高等数学,线性代数,离散数学,晕了,少壮不努力,老大写程序)。
实际上可以通过求F(n)的通项公式,使算法复杂度降到O(1)。在这里先给出通项公式,再来谈如果求通项公式。
公式:
范例代码:
{
return Math.Sqrt(5) / 5 * (Math.Pow((1 + Math.Sqrt(5)) / 2, data) - Math.Pow((1 - Math.Sqrt(5)) / 2, data));
}
以下是摘自维基百科的关于通项公式的求法(原来求递归数例的通项公式有好几种方法,以下解法用到的是构造等比数例的方法):
这个通项公式非常奇妙。看上去它好像是一个无理数,但实际上只要n>0,它的值都是整数。。。。。。。。。。
唉,看来这年头,学不好大学数学,是很难写出牛B的代码滴,
4、线性代数解法
线性代数的解法我还没有看懂,在这里就不贴具体内容了。。。。。。
线性代数解法可以推出如下的近似公式:
关于Fibonacci数列还有很多值得深入研究的地方,再一次强烈感觉到科学家们真是伟大。。。。。。