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

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

之前那幾種算法時間復(fù)雜度最好的也只是O(n)

下面是幾種高效解法,時間復(fù)雜度都是O(log n)

7.? 二分遞歸解法

設(shè)n∈R,則有:

F[n]=F[n/2+1]2?F[n/2?1]2=(2F[n/2?1]+F[n/2])F[n/2]????? 當(dāng)n為偶數(shù)時

F[n]=F[n/2]2+F[n/2+1]2????????????????????????? ? ? ? ?? ???????????????? 當(dāng)n為奇數(shù)時

下面用遞歸寫出解法,真是很簡單

因為這是二元遞歸函數(shù),所以加上上篇的緩存遞歸函數(shù)裝飾器和動態(tài)增加棧空間函數(shù)

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

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

??? @recursive_function_cache

??? def Calculate_Fibonacci_sequence (n: int) -> int:

? ? ? ? '返回單項的二分遞歸解法'

? ? ? ? if n >= 2:

??????????? one_half_n = n >> 1

? ? ? ? ? ? if n & 1 == 0:? #當(dāng)n為偶數(shù)項

? ? ? ? ? ? ? ? one_half_fib_n = Calculate_Fibonacci_sequence(one_half_n)

? ? ? ? ? ? ? ? one_half_fib_n_minus_one = Calculate_Fibonacci_sequence(one_half_n - 1)

? ? ? ? ? ? ? ? return (one_half_fib_n_minus_one * 2 + one_half_fib_n) * one_half_fib_n

? ? ? ? ? ? else:? #當(dāng)n為奇數(shù)項

? ? ? ? ? ? ? ? return Calculate_Fibonacci_sequence(one_half_n) ** 2 + Calculate_Fibonacci_sequence(one_half_n + 1) ** 2

? ? ? ? elif n == 1:

? ? ? ? ? ? return 1

? ? ? ? elif n == 0:

? ? ? ? ? ? return 0

? ? if n>=0:

? ? ? ? return Calculate_Fibonacci_sequence(n)

? ? else:

? ? ? ? return None

dynamic_increase_recursion_limit('Fibonacci_sequence_07(1000000)')

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

Total time: 0.076837秒

算第100萬項只用時這么點,按前面最快的for迭代解法速度這點時間也只能算到3萬多。看起來是高效多了

具體的時間復(fù)雜度是怎樣的呢

這二分法的遞歸形式分析起來有點麻煩

那下面我寫成迭代形式再分析時間復(fù)雜度吧


8.? 二分迭代解法

用迭代形式實現(xiàn)這二分解法,看看用時如何

程序如下:

from collections import deque

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

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

? ? def Calculate_Fibonacci_sequence (n: int) -> int:

? ? ? ? '返回單項的二分迭代解法'

? ? ? ? Even = True

? ? ? ? Odd = False

? ? ? ? if n >= 2:

? ? ? ? ? ? fib_n_tree = [n, []]? #數(shù)據(jù)存放格式是列表里前后兩項,前項是n,后項是對應(yīng)第n項Fibonacci數(shù)或是包含兩個子節(jié)點的一個列表

? ? ? ? ? ? fib_n_tier_node_queue = deque()

? ? ? ? ? ? fib_n_cache = dict()

? ? ? ? ? ? fib_merge_stack = []

? ? ? ? ? ? def generating_fib_n_tree(n):

? ? ? ? ? ? ? ? nonlocal fib_n_tier_node_queue, fib_n_cache, current_root

? ? ? ? ? ? ? ? if n >= 2:

? ? ? ? ? ? ? ? ? ? if n in fib_n_cache:

? ? ? ? ? ? ? ? ? ? ? ? child_nodes = dict.get(fib_n_cache, n)

? ? ? ? ? ? ? ? ? ? else:

? ? ? ? ? ? ? ? ? ? ? ? child_nodes = [n, []]

? ? ? ? ? ? ? ? ? ? ? ? fib_n_tier_node_queue.append(child_nodes)

? ? ? ? ? ? ? ? ? ? ? ? fib_n_cache.update({n: child_nodes})

? ? ? ? ? ? ? ? elif n == 1:

? ? ? ? ? ? ? ? ? ? child_nodes = (n, 1)

? ? ? ? ? ? ? ? elif n == 0:

? ? ? ? ? ? ? ? ? ? child_nodes = (n, 0)

? ? ? ? ? ? ? ? current_root[1].append(child_nodes)? #將產(chǎn)生的子節(jié)點往current_root里裝子節(jié)點的列表里壓入

? ? ? ? ? ? fib_n_tier_node_queue.append(fib_n_tree)

? ? ? ? ? ? while len(fib_n_tier_node_queue) > 0:? #先從上至下建立二分樹

? ? ? ? ? ? ? ? current_root = fib_n_tier_node_queue.popleft()

? ? ? ? ? ? ? ? n_of_current_root = current_root[0]

? ? ? ? ? ? ? ? one_half_n = n_of_current_root >> 1

? ? ? ? ? ? ? ? if n_of_current_root & 1 == 0:? #當(dāng)n_of_current_root為偶數(shù)項

? ? ? ? ? ? ? ? ? ? generating_fib_n_tree(one_half_n)? #往fib_n_tree里先存兩者中較大的數(shù)字

? ? ? ? ? ? ? ? ? ? generating_fib_n_tree(one_half_n - 1)

? ? ? ? ? ? ? ? ? ? fib_merge_stack.append((current_root, Even))

? ? ? ? ? ? ? ? else:? #當(dāng)n_of_current_root為奇數(shù)項

? ? ? ? ? ? ? ? ? ? generating_fib_n_tree(one_half_n + 1)? #往fib_n_tree里先存兩者中較大的數(shù)字

? ? ? ? ? ? ? ? ? ? generating_fib_n_tree(one_half_n)

? ? ? ? ? ? ? ? ? ? fib_merge_stack.append((current_root, Odd))

? ? ? ? ? ? while len(fib_merge_stack) > 0:? #再二分樹從下至上歸并算出結(jié)果

? ? ? ? ? ? ? ? current_task = fib_merge_stack.pop()

? ? ? ? ? ? ? ? current_root = current_task[0]

? ? ? ? ? ? ? ? odevity = current_task[1]

? ? ? ? ? ? ? ? list_of_current_child_node = current_root[1]

? ? ? ? ? ? ? ? large_value_of_current_child_node = list_of_current_child_node[0][1]

? ? ? ? ? ? ? ? small_value_of_current_child_node = list_of_current_child_node[1][1]

? ? ? ? ? ? ? ? if odevity:

? ? ? ? ? ? ? ? ? results = (small_value_of_current_child_node * 2 +

large_value_of_current_child_node) * large_value_of_current_child_node

? ? ? ? ? ? ? ? else:

? ? ? ? ? ? ? ? ? ? results = small_value_of_current_child_node ** 2 + large_value_of_current_child_node ** 2

? ? ? ? ? ? ? ??current_root[1] = results

? ? ? ? ? ? return fib_n_tree[1]

? ? ? ? elif n == 1:

? ? ? ? ? ? return 1

? ? ? ? elif n == 0:

? ? ? ? ? ? return 0

? ? if n >= 0:

? ? ? ? return Calculate_Fibonacci_sequence(n)

? ? else:

? ? ? ? return None

Fibonacci_sequence_08(1000000)

還是算第100萬位,Total time: 0.076679秒

用時幾乎一樣!用時縮短了158us只能算計時誤差范疇

現(xiàn)在來分析下這個解法的時間復(fù)雜度

主干就是建立二叉樹的迭代,對n不斷二分,搜索新子節(jié)點,迭代次數(shù)是2*log2(n),時間復(fù)雜度就是O(log n)

未完待續(xù)……

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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