……續(xù)上回Fibonacci數(shù)列高效解法大全及時(shí)間復(fù)雜度分析 連載【3】
之前那幾種算法時(shí)間復(fù)雜度最好的也只是O(n)
下面是幾種高效解法,時(shí)間復(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ù)時(shí)
F[n]=F[n/2]2+F[n/2+1]2????????????????????????? ? ? ? ?? ???????????????? 當(dāng)n為奇數(shù)時(shí)
下面用遞歸寫出解法然磷,真是很簡單
因?yàn)檫@是二元遞歸函數(shù)捆憎,所以加上上篇的緩存遞歸函數(shù)裝飾器和動(dòng)態(tài)增加椫伲空間函數(shù)
def Fibonacci_sequence_07 (n: int) -> int:? #參數(shù)n是表示求第n項(xiàng)Fibonacci數(shù)
? ? assert isinstance(n, int), 'n is an error of non-integer type.'
??? @recursive_function_cache
??? def Calculate_Fibonacci_sequence (n: int) -> int:
? ? ? ? '返回單項(xiàng)的二分遞歸解法'
? ? ? ? if n >= 2:
??????????? one_half_n = n >> 1
? ? ? ? ? ? if n & 1 == 0:? #當(dāng)n為偶數(shù)項(xiàng)
? ? ? ? ? ? ? ? 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ù)項(xiàng)
? ? ? ? ? ? ? ? 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萬項(xiàng)Fibonacci數(shù)來測量下用時(shí)
Total time: 0.076837秒
算第100萬項(xiàng)只用時(shí)這么點(diǎn)边坤,按前面最快的for迭代解法速度這點(diǎn)時(shí)間也只能算到3萬多〕迹看起來是高效多了
具體的時(shí)間復(fù)雜度是怎樣的呢
這二分法的遞歸形式分析起來有點(diǎn)麻煩
那下面我寫成迭代形式再分析時(shí)間復(fù)雜度吧
8.? 二分迭代解法
用迭代形式實(shí)現(xiàn)這二分解法,看看用時(shí)如何
程序如下:
from collections import deque
def Fibonacci_sequence_08 (n: int) -> int:? #參數(shù)n是表示求第n項(xiàng)Fibonacci數(shù)
? ? assert isinstance(n, int), 'n is an error of non-integer type.'
? ? def Calculate_Fibonacci_sequence (n: int) -> int:
? ? ? ? '返回單項(xiàng)的二分迭代解法'
? ? ? ? Even = True
? ? ? ? Odd = False
? ? ? ? if n >= 2:
? ? ? ? ? ? fib_n_tree = [n, []]? #數(shù)據(jù)存放格式是列表里前后兩項(xiàng)伙窃,前項(xiàng)是n呻右,后項(xiàng)是對應(yīng)第n項(xiàng)Fibonacci數(shù)或是包含兩個(gè)子節(jié)點(diǎn)的一個(gè)列表
? ? ? ? ? ? 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é)點(diǎn)往current_root里裝子節(jié)點(diǎn)的列表里壓入
? ? ? ? ? ? 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ù)項(xiàng)
? ? ? ? ? ? ? ? ? ? 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ù)項(xiàng)
? ? ? ? ? ? ? ? ? ? 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秒
用時(shí)幾乎一樣肛宋!用時(shí)縮短了158us只能算計(jì)時(shí)誤差范疇
現(xiàn)在來分析下這個(gè)解法的時(shí)間復(fù)雜度
主干就是建立二叉樹的迭代沉帮,對n不斷二分,搜索新子節(jié)點(diǎn)其屏,迭代次數(shù)是2*log2(n)熄云,時(shí)間復(fù)雜度就是O(log n)
未完待續(xù)……