精益求精——斐波那契数列的logn解法

简介: 精益求精——斐波那契数列的logn解法

缘起:兔子数列

斐波那契数列指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89...

这个数列从第3项开始,每一项都等于前两项之和。它因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。

斐波那契数列递推公式:

斐波那契数列很强,在现代物理、准晶体结构、化学等领域,斐波那契数列都有直接的应用。

通常求解斐波那契数列的算法有递归算法和动态规划算法,递归算法直接利用斐波那契数列的递推公式求解,递归调用递推公式,使时间复杂度为指数阶,当数列元素很多时,求解过程将是一场灾难。再来看动态规划,它会动态存储运算过程中的结果,使时间复杂度降到了多项式阶,较递归算法好了很多,那有没有更好的算法呢,我们知道,多项式阶时间复杂度好于指数阶时间复杂度,而对数阶时间复杂度比多项式阶时间复杂度更为优越,那有没有对数阶时间复杂度的算法可以求解斐波那契数列呢?答案是:有,必须的,嘿嘿。

计算一个数的幂

在讲解斐波那契数列求解之前,我们先来看看怎么更好的求解一个数的连乘,即一个数的幂次。比如求一个数的n次幂,最简单的做法是先求前两个数的乘积,得到的结果再去乘以第三个数,得到乘积再去乘以第四个数,不断重复,一直到n个数都乘完。这看上去很自然,那它的时间复杂度是多少呢?很明显,是O(n),即多形式阶。

除了上面的方法,我们可以利用分治的思想,让n个数先两两相乘,得到的结果再两两相乘,可用递归算法求解,求解过程如下图所示

看,是不是二叉树的感觉出来了,很明显,有了类似树的结构,运算的时间复杂度就是O(logn)

具体计算公式如下

我们将数推广到矩阵,比如2x2阶矩阵,有类似的结论,只不过数的相乘就一次乘法运算,而两个2x2阶矩阵的相乘需要12次算术运算(相乘后的矩阵中,每个元素都需要两次乘法和一次加法获得),是两个数相乘所需运算量的12倍,但利用上面分治的思想,矩阵连乘运算的时间复杂度仍然是对数阶的。

数学归纳法

令P(n)是关于整数n的某个命题,假定我们需要证明P(n)对于所有正整数n为真,一种重要做法是:

(a) 证明P(1)为真;

(b) 证明“如果P(1),P(2)....P(n-1)全部为真,那么P(n)也为真”,这个证明应对任意正整数n成立.

这就是著名的数学归纳法。

斐波那契数列的恒等式

斐波那契数列满足许多有趣的恒等式,其中一个恒等式可以用矩阵来表示为

我们可以用数学归纳法证明这个公式:

当n=1,F0=0,F1=1,F2=2,等式成立。

现在假设n-1项斐波那契数列满足恒等式,即

证明n项斐波那契数列也满足恒等式,根据矩阵乘法的定义,我们可以得到

这个恒等式有什么用呢,结合上一小节的结论我们不难发现,通过这个恒等式,我们就将斐波那契数列的求解变成了一个特殊矩阵的连乘,这样会使时间复杂度变成对数阶!!哈哈,我们找到了可以求解斐波那契数列并且时间复杂度是对数阶的算法!!

代码

import numpy as np
 
# 特殊矩阵
A = np.array([[1, 1], [1, 0]])
 
 
def fibonacci(n):
    if n <= 1:
        return A
    # 根据恒等式求解特殊矩阵连乘
    multi = np.dot(fibonacci(n>>1), fibonacci(n>>1))
    return multi if n & 1 == 0 else np.dot(multi, A)
 
 
# 算法主体
def run():
    # 数列元素个数
    N = 11
    # 求解斐波那契数列
    result = fibonacci(N-1)
    print("斐波那契数列第{}项是:{}".format(N, result[0][0]))
 
 
if __name__ == "__main__":
    run()

程序运行结果如下

斐波那契数列第11项是:89

作者这水平有限,有不足之处欢迎留言指正

相关文章
|
2月前
斐波那契数列
【10月更文挑战第19天】斐波那契数列。
36 3
|
3月前
|
Java
01_斐波那契数列
01_斐波那契数列
|
7月前
|
算法 索引
Leetcode算法系列| 1. 两数之和(四种解法)
Leetcode算法系列| 1. 两数之和(四种解法)
(1188:1201:)斐波那契数列
(1188:1201:)斐波那契数列
155 0
|
机器学习/深度学习 开发工具
斐波那契数列的四种实现
在编程教程中提到斐波那契数列,通常都是用来讲解递归函数。当一个关于 N 的问题可以转换为关于 N - k 的同样问题时,它就可以尝试用递归的思路来解决。
斐波那契数列问题
斐波那契数列问题
102 0
|
前端开发 程序员 测试技术
斐波那契数列的多种解法
斐波那契数列的多种解法
斐波那契数列的多种解法
|
算法
30.斐波那契数列
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 n<=39
76 0
30.斐波那契数列
|
机器学习/深度学习 算法
斐波那契数列的四种解法
斐波那契数列的四种解法
斐波那契数列的四种解法
|
算法 JavaScript 前端开发
☮斐波那契数列与动态规划
☮斐波那契数列与动态规划
123 0
☮斐波那契数列与动态规划