zoukankan      html  css  js  c++  java
  • 第六篇:算法之矩阵计算斐波那契数列

    算法之矩阵计算斐波那契数列

     

    算法之矩阵计算斐波那契数列

    本节内容

    1. 斐波那契介绍
    2. 普通方式求解斐波那契
    3. 矩阵概念
    4. 矩阵求幂
    5. 矩阵求解斐波那契

    1.斐波那契介绍

    斐波那契数列有关十分明显的特点,那是:前面相邻两项之和,构成了后一项。即f(n)=f(n-1)+f(n-2),f(0)=0,f(1)=f(2)=1,推导下去f(3)=2,f(4)=3,f(5)=5。。。。。。

    2.普通方式求解斐波那契

    按照上面提供的推导公式,普通方式求解斐波那契数列代码如下:

    复制代码
    1 def normal(n):
    2     a,b,c=0,1,1
    3     while n:
    4         a,b,c=b,c,b+c
    5         n-=1
    6     return a
    复制代码

    使用上面的方式求解第n项斐波那契数列的时间复杂度为O(n),也就是说,时间复杂度随着n的增长而线性增长。

    3.矩阵概念

    开始,先来介绍一下矩阵的概念:在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方程组的系数及常数所构成的方阵。

    这里不介绍矩阵的各方面知识了,如果那样的话。。。就是一篇数学笔记了。。。这里只讲解矩阵相乘的概念。

    矩阵相乘:矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有意义。一般单指矩阵乘积时,指的便是一般矩阵乘积。一个m×n的矩阵就是m×n个数排成m行n列的一个数阵。由于它把许多数据紧凑的集中到了一起,所以有时候可以简便地表示一些复杂的模型。

    设A为m*p的矩阵,B为p*n的矩阵,那么称m*n的矩阵C为矩阵A与B的乘积,记作C=AB:

    4.矩阵求幂

    上面已经介绍过了矩阵相乘的概念了,那么,斐波那契该怎么由矩阵标示呢?

    从第三项开始,每一项都是前两项之和。 F(n)=F(n−1)+F(n−2), n⩾3 把斐波那契数列中 相邻的两项F(n)和F(n−1)写成一个2×1的矩阵。

    斐波那契数列用矩阵推导如下:

    求F(n)等于求二阶矩阵的n - 1次方,结果取矩阵第一行第一列的元素。

    问题转换为二阶矩阵的n次幂。

    而计算二阶矩阵的N次幂运算,由于二阶矩阵乘法满足结合律,这样,可以快速计算二阶矩阵的n次幂运算。

    假设A为一个二阶矩阵,则A的幂运算满足下面的条件:

    A**6=A**3∗A**3

    A**7=A**3∗A**3∗A**1=A**4*A**2*A**1

    在这里,我们可以类似地把A看做是二进制中的2,2**7=2**4*2**2*2**1也就是说可以把矩阵的幂转换成二进制来表示。从而可以将n次幂拆解成长度为logn的二进制数来表示:7=111(二进制)。

    这就是快速求二阶矩阵的核心方法。

    5. 矩阵求解斐波那契

    前戏做足了,下面就该秀代码了。

    复制代码
     1 def multi(a,b):  # 计算二阶矩阵的相乘
     2     c=[[0,0],[0,0]]  # 定义一个空的二阶矩阵
     3     for i in range(2):
     4         for j in range(2):
     5             for k in range(2):  # 新二阶矩阵的值计算
     6                 c[i][j]=c[i][j]+a[i][k]*b[k][j]
     7     return c
     8 
     9 
    10 def matrix(n):
    11     base=[[1,1],[1,0]]  # 元矩阵,这里可以把元矩阵看做是2**0=1
    12     ans=[[1,0],[0,1]]  # 结果矩阵  最开始的结果矩阵也可以看做是1,因为这个矩阵和任意二阶A矩阵相乘结果都是A
    13     while n:
    14         if n&1:  # 取n的二进制的最后一位和1做与运算,如果最后一位是1,则进入if体内部
    15             ans=multi(ans,base)  # 如果在该位置n的二进制为1,则计算ans和base矩阵
    16         base=multi(base,base)  # base矩阵相乘,相当于初始base矩阵的幂*2
    17         n>>=1  # n的二进制往右移一位
    18     return ans[0][1]  # 最后获取到的二阶矩阵的[0][1]即f(n)的值
    复制代码

    最后把例子的完整代码贴出来:

    复制代码
     1 import time
     2 
     3 
     4 def multi(a,b):
     5     c=[[0,0],[0,0]]
     6     for i in range(2):
     7         for j in range(2):
     8             for k in range(2):
     9                 c[i][j]=c[i][j]+a[i][k]*b[k][j]
    10     return c
    11 
    12 
    13 def matrix(n):
    14     base=[[1,1],[1,0]]
    15     ans=[[1,0],[0,1]]
    16     while n:
    17         if n&1:
    18             ans=multi(ans,base)
    19         base=multi(base,base)
    20         n>>=1
    21     # for i in range(2):
    22     #     print(ans[i])
    23     return ans[0][1]
    24 
    25 def normal(n):
    26     a,b,c=0,1,1
    27     while n:
    28         a,b,c=b,c,b+c
    29         n-=1
    30     return a
    31 
    32 n=int(input(">>>"))
    33 start=time.time()
    34 print("Normal:",normal(n))
    35 print("use:",time.time()-start)
    36 start=time.time()
    37 print("Matrix:",matrix(n))
    38 print("use:",time.time()-start)
    39 #计算结果
    40 >>>65536
    41 Normal: 731992144602......
    42 use: 0.07219505310058594
    43 Matrix: 731992144602......
    44 use: 0.023076772689819336
    复制代码

    可以看出来当n的值越来越大的时候,两种方式计算出结果的时间差距将越来越大,正常的计算时间复杂度是O(n),矩阵求值的时间复杂度是O(logn)。

    后记:

    由此可以看出,使用推导式f(n)=f(n-1)+f(n-2)求斐波那契的第n项的算法复杂度极限为O(n),这是一维世界下的极限。将其从一维上升到二维,用二阶矩阵推导斐波那契数列时,计算的算法复杂度为O(logn),也就是说,使用升维的手段将一维空间进行扭曲从而将距离缩短,可以更快的计算出结果。

    由此推导出如果人来要突破光速的极限,需要将现有的三维空间升级到四维空间,扭曲空间从而缩短距离,达到突破光速的目的。

     
    分类: 算法
  • 相关阅读:
    windbg条件断点总结
    使用openssl命令剖析RSA私钥文件格式
    RSA读取密钥——使用openssl编程
    OPENSSL中RSA私钥文件(PEM格式)解析【一】
    电商系统架构——系统鸟瞰图
    构建高并发高可用的电商平台架构实践
    一些PHP性能的优化
    CentOS的Gearman安装
    php安装gearman扩展实现异步分步式任务
    使用 Gearman 实现分布式处理
  • 原文地址:https://www.cnblogs.com/weiman3389/p/6224875.html
Copyright © 2011-2022 走看看