Fibonacci數(shù)列高效解法大全及時間復(fù)雜度分析 連載【8】

在數(shù)學(xué)上袭祟,斐波那契數(shù)列是以遞歸的方法來定義

……續(xù)上回Fibonacci數(shù)列高效解法大全及時間復(fù)雜度分析 連載【7】

之前的篇章把各種Fibonacci數(shù)列的基本算法討論過了

那么是否可以做到更快呢热幔,有什么加速手段

這篇來說下

首先第一個手段是改進算法的加速

16.? 快速平方的矩陣解法

Fibonacci數(shù)列高效解法大全及時間復(fù)雜度分析 連載【5】這篇里說過矩陣解法

矩陣法雖然跟二進制模冪解法時間復(fù)雜度一樣闸迷,可算第100萬項斐波那契數(shù)用時是二進制模冪解法的10倍宣渗。這是因為這算法的時間常數(shù)項大

里面用到了矩陣乘法班巩,通用矩陣乘法算法的時間復(fù)雜度是階數(shù)n的O(n^3)蔓罚。也就是對一個二階矩陣竿奏,分解步驟中有8次乘法训裆,非常耗時眶根,造成矩陣解法時間常數(shù)項很大

之前程序是直接用的numpy庫做矩陣乘法,numpy庫里就是通用矩陣乘法算法

然而缭保,對斐波那契數(shù)的矩陣解法汛闸,只需對二階矩陣做運算。而其中的二階矩陣平方步驟是有更小時間復(fù)雜度算法的

二階矩陣快速平方算法的時間復(fù)雜度為階數(shù)2的O(2^(log2(5)))

也就是二階矩陣一次平方運算分解步驟中只用做5次乘法艺骂。比通用矩陣算法的8次降低了不少

但是诸老,對斐波那契數(shù)矩陣解法而言,矩陣乘法步驟是其中的時間常數(shù)項钳恕,縮短矩陣乘法用時只是降低整個算法的常數(shù)項别伏,可并不降低整個算法的時間復(fù)雜度

下面就是我寫的程序

import numpy

import gmpy2

def fast_power_of_second_order_matrix(input_matrix: 'matrix', exponential: int) -> 'matrix':

? ? assert isinstance(exponential, int), 'Exponential is an error of non-integer type.'

? ? assert exponential >= 0, 'The exponent cannot be negative.'

? ? assert input_matrix.shape == (2, 2), 'It can only be a second-order matrix'

? ? if numpy.min_scalar_type(input_matrix) in (numpy.dtype(bool), numpy.dtype(int), numpy.dtype(float), numpy.dtype(complex)):

? ? ? ? output_matrix = numpy.asmatrix(numpy.identity(2, dtype = numpy.min_scalar_type(input_matrix)))? #根據(jù)輸入矩陣的標量類型,把output_matrix初始化為相同類型的單位矩陣

? ? elif numpy.issubsctype(input_matrix, numpy.dtype(object)):

? ? ? ? for matrix_element in input_matrix.flat:

? ? ? ? ? ? if type(matrix_element) not in (type(gmpy2.mpz()), type(gmpy2.xmpz()), type(gmpy2.mpq()), type(gmpy2.mpfr()), type(gmpy2.mpc()), int, float):

? ? ? ? ? ? ? ? raise TypeError('The matrix can only be of Boolean or numeric type.')

? ? ? ? output_matrix = numpy.mat(((gmpy2.mpz(1), gmpy2.mpz(0)), (gmpy2.mpz(0), gmpy2.mpz(1))))? #初始化值為mpz類型的單位矩陣

? ? else:

? ? ? ? raise TypeError('The matrix can only be of Boolean or numeric type.')

? ? def square_of_second_order_matrix(input_second_order_matrix: 'matrix') -> 'matrix':

? ? ? ? output_second_order_matrix = numpy.copy(input_second_order_matrix)

? ? ? ? sum_of_main_diagonal = output_second_order_matrix[0, 0] + output_second_order_matrix[1, 1]

? ? ? ? product_of_antidiagonal = output_second_order_matrix[0, 1] * output_second_order_matrix[1, 0]

??????? output_second_order_matrix[0, 0] **= 2

? ? ? ? output_second_order_matrix[0, 0] += product_of_antidiagonal

? ? ? ? output_second_order_matrix[0, 1] *= sum_of_main_diagonal

? ? ? ? output_second_order_matrix[1, 0] *= sum_of_main_diagonal

? ? ? ? output_second_order_matrix[1, 1] **= 2

? ? ? ? output_second_order_matrix[1, 1] += product_of_antidiagonal

? ? ? ? return output_second_order_matrix

? ? intermediate_variable = numpy.copy(input_matrix)

? ? while True:

? ? ? ? if exponential & 1 == 1:

? ? ? ? ? ? output_matrix *= intermediate_variable

? ? ? ? ? ? if exponential == 1: break

? ? ? ? intermediate_variable = square_of_second_order_matrix(intermediate_variable)

? ? ? ? exponential >>= 1

? ? return output_matrix

import numpy.matlib

from gmpy2 import mpz

def Fibonacci_sequence_06 (n: int) -> int:? #參數(shù)n是表示求第n項Fibonacci數(shù)

? ? '返回單項的二階矩陣快速平方解法'

? ? assert isinstance(n, int), 'n is an error of non-integer type.'

? ? Use_threshold_of_fast_power = 100000

? ? if n >= 2:

? ? ? ? fib_matrix = numpy.mat(((mpz(1), mpz(1)), (mpz(1), mpz(0))))

? ? ? ? if n > Use_threshold_of_fast_power:

? ? ? ? ? ? fib_matrix = fast_power_of_second_order_matrix(fib_matrix, n - 1)

? ? ? ? else:

? ? ? ? ? ? fib_matrix **= n - 1

? ? ? ? return fib_matrix[0,0]

? ? elif n == 1:

? ? ? ? return 1

? ? elif n == 0:

? ? ? ? return 0

? ? else:

? ? ? ? return None

Fibonacci_sequence_06(1000000)

用算到第100萬項Fibonacci數(shù)來測量下用時

Total time: 0.036093秒

比之前用通用矩陣乘法庫的程序縮短了15%的時間

注意忧额,那么一大段程序是有基礎(chǔ)開銷的

所以在非大數(shù)的時候用這個反而會不如通用庫快

怎么辦呢

加一個閾值判別厘肮。當N大于閾值之后,才用這個二階矩陣快速平法算法睦番,數(shù)不大時就調(diào)用通用庫

搞定

------------------------

算Fibonacci數(shù)的快速算法已經(jīng)寫了4種类茂,算法時間復(fù)雜度皆為O(log n),但常數(shù)項不同托嚣。

矩陣快速冪解法每步中兩個大整數(shù)乘法是8次

快速平方的矩陣解法每步中兩個大整數(shù)乘法是5次

二分解法每步中兩個大整數(shù)乘法是3次

二進制模冪解法每步中兩個大整數(shù)乘法是2次

有趣巩检,剛好是個Fibonacci數(shù)列

歡迎點贊、留言

未完待續(xù)……

Fibonacci數(shù)列高效解法大全及時間復(fù)雜度分析 連載【9】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末示启,一起剝皮案震驚了整個濱河市兢哭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夫嗓,老刑警劉巖迟螺,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舍咖,居然都是意外死亡矩父,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門排霉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窍株,“玉大人,你說我怎么就攤上這事〖欣眩” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵辙诞,是天一觀的道長辙售。 經(jīng)常有香客問我,道長飞涂,這世上最難降的妖魔是什么旦部? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮较店,結(jié)果婚禮上士八,老公的妹妹穿的比我還像新娘。我一直安慰自己梁呈,他們只是感情好婚度,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著官卡,像睡著了一般蝗茁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寻咒,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天哮翘,我揣著相機與錄音,去河邊找鬼毛秘。 笑死饭寺,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的叫挟。 我是一名探鬼主播艰匙,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼霞揉!你這毒婦竟也來了旬薯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤适秩,失蹤者是張志新(化名)和其女友劉穎绊序,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秽荞,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡骤公,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了扬跋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阶捆。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出洒试,到底是詐尸還是另有隱情倍奢,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布垒棋,位于F島的核電站卒煞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叼架。R本人自食惡果不足惜畔裕,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乖订。 院中可真熱鬧扮饶,春花似錦、人聲如沸乍构。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜡吧。三九已至毫蚓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昔善,已是汗流浹背元潘。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留君仆,地道東北人翩概。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像返咱,于是被迫代替她去往敵國和親钥庇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容