Fibonacci数列高效解法大全及时间复杂度分析 连载【4】

……续上回Fibonacci数列高效解法大全及时间复杂度分析 连载【3】

之前那几种算法时间复杂度最好的也只是O(n)

下面是几种高效解法,时间复杂度都是O(log n)

7.  二分递归解法

设n∈R,则有:

F[n]=F[n/2+1]²−F[n/2−1]²=(2F[n/2−1]+F[n/2])F[n/2]      当n为偶数时

F[n]=F[n/2]²+F[n/2+1]²                                                    当n为奇数时

下面用递归写出解法,真是很简单

因为这是二元递归函数,所以加上上篇的缓存递归函数装饰器和动态增加栈空间函数

def Fibonacci_sequence_07 (n: int) -> int:  #参数n是表示求第n项Fibonacci数

    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:  #当n为偶数项

                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:  #当n为奇数项

                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数来测量下用时

Total time: 0.076837秒

算第100万项只用时这么点,按前面最快的for迭代解法速度这点时间也只能算到3万多。看起来是高效多了

具体的时间复杂度是怎样的呢

这二分法的递归形式分析起来有点麻烦

那下面我写成迭代形式再分析时间复杂度吧


8.  二分迭代解法

用迭代形式实现这二分解法,看看用时如何

程序如下:

from collections import deque

def Fibonacci_sequence_08 (n: int) -> int:  #参数n是表示求第n项Fibonacci数

    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, []]  #数据存放格式是列表里前后两项,前项是n,后项是对应第n项Fibonacci数或是包含两个子节点的一个列表

            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)  #将产生的子节点往current_root里装子节点的列表里压入

            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:  #当n_of_current_root为偶数项

                    generating_fib_n_tree(one_half_n)  #往fib_n_tree里先存两者中较大的数字

                    generating_fib_n_tree(one_half_n - 1)

                    fib_merge_stack.append((current_root, Even))

                else:  #当n_of_current_root为奇数项

                    generating_fib_n_tree(one_half_n + 1)  #往fib_n_tree里先存两者中较大的数字

                    generating_fib_n_tree(one_half_n)

                    fib_merge_stack.append((current_root, Odd))

            while len(fib_merge_stack) > 0:  #再二分树从下至上归并算出结果

                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只能算计时误差范畴

现在来分析下这个解法的时间复杂度

主干就是建立二叉树的迭代,对n不断二分,搜索新子节点,迭代次数是2*log2(n),时间复杂度就是O(log n)

未完待续……

Fibonacci数列高效解法大全及时间复杂度分析 连载【5】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容