算法之矩阵计算斐波那契数列
算法之矩阵计算斐波那契数列
本节内容
- 斐波那契介绍
- 普通方式求解斐波那契
- 矩阵概念
- 矩阵求幂
- 矩阵求解斐波那契
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),也就是说,使用升维的手段将一维空间进行扭曲从而将距离缩短,可以更快的计算出结果。
由此推导出如果人来要突破光速的极限,需要将现有的三维空间升级到四维空间,扭曲空间从而缩短距离,达到突破光速的目的。
转载于:https://www.cnblogs.com/huxianglin/p/5995649.html
算法之矩阵计算斐波那契数列相关推荐
- 算法 | 详解斐波那契数列问题
14天阅读挑战赛 本篇是学习了<趣学算法(第2版)> 第一章之后总结的. 上一篇讲到了等比数列求和问题,求Sn=1+2+22+23+...+263=?S_n = 1 + 2 + 2^2 + ...
- 【js算法】js斐波那契数列的多种算法
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列" ...
- 【使用递归玩通关汉诺塔游戏】算法01-递归(斐波那契数列、汉罗塔问题)-java实现
递归 定义:在一个方法(函数)的内部调用该方法(函数)本身的编程方式 简而言之就是 "自己调自己" 在玩游戏之前让我们先对递归有一个简单的了解吧! 5.1 递归简介 递归必须有一个 ...
- 【算法编程】斐波那契数列
题目来源:牛客网剑指offer 题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项.n<=39 C++:5ms 476k #include <iostr ...
- 递归、尾递归、迭代算法【在 斐波拉契数列】上的实现
/* 递归: [逆序]从未知点推到已知点,[顺序]代入已知点结果,从已知点带入并计算到未知点,最终到终点 尾递归: 从起点开始,依顺序计算结果,并无限靠近最终目标点 迭代: 从 ...
- 算法—递归生成斐波那契数列
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.递归生成斐波那契数列 二.使用步骤 1.伪代码 2.c 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如 ...
- c语言斐波那契数列_神奇的数列——斐波那契数列
斐波那契数列之美 斐波那契是一位数学家,生于公元1170年,籍贯大概是比萨,卒于1240年后.1202年,他撰写了<珠算原理>(Liber Abaci)一书.他是第一个研究了印度和阿拉伯数 ...
- 数据结构与算法--再谈递归与循环(斐波那契数列)
再谈递归与循环 在某些算法中,可能需要重复计算相同的问题,通常我们可以选择用递归或者循环两种方法.递归是一个函数内部的调用这个函数自身.循环则是通过设置计算的初始值以及终止条件,在一个范围内重复运算. ...
- 求解斐波那契数列(Fibonacci Numbers)算法居然有9种,你知道哪几种吗?
By LongLuo 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为&q ...
最新文章
- Spark shuffle调优
- c语言中常用的程序,C语言一些常用语句
- 你真的会停止线程吗?
- 2019长安大学ACM校赛网络同步赛 L	XOR (规律,数位DP)
- kettle-实现每个分组的前N的数据
- python交通流预测代码_使用ARIMA模型进行的短时交通流预测和结果分析
- 常见条码及其相关概念简介
- [体验编译原理]编写简易计算器
- python 双色球 大乐透 5注随机选号
- 偶遇的webshell,那得冲一波
- Java 参数类型后面三个点,可变参数列表
- 解决微信设置字体大小对 rem 适配方式的影响
- 测试自己移动速度的软件,鼠标灵敏度测试检测工具 测试鼠标的灵敏度与移动速度...
- JS仿写刮刮乐小例子
- 在《2000年通则》中,根据卖方承担义务的不同,将13种贸易术语划分为下列四组:...
- python模块总结_Python常用模块资料总结和归纳
- ssh开启图形界面_分享|3 个 Linux 上的 SSH 图形界面工具
- POI导出excel,按照父子节点进行分级显示
- 设置WIN 7 截图工具的快捷方式
- OPENCV2.4.9配置
热门文章
- python class类里给列表排序_python笔记:Class(类)
- How to ignore files and directories in subversion?
- BZOJ1834 [ZJOI2010]network 网络扩容
- Unity手游之路四3d旋转-四元数,欧拉角和变幻矩阵
- Javascript中正则表达式的全局匹配模式
- 洛杉矶手机资费9.9美元包打一年
- phpweb2.0 开发实战 ----- 配置虚拟主机
- 一些奇妙的线段树操作
- 【集合工具类:Collections】
- [HAOI2008]移动玩具