python斐波那契数列前20项_斐波那契数列与Python的尾递归蹦床 连载【4】

dd6178a4a6af3b9350fe8f829cf62e44.png

2f5fb6531986bb9f033a1f7a2025ad82.png

……续上回

fss.sosei:斐波那契数列与Python的尾递归蹦床 连载【3】​zhuanlan.zhihu.com
1f1ea9746aa916f5cf1633a56e4c968d.png

之前那几种算法时间复杂度最好的也只是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)

未完待续……

fss.sosei:斐波那契数列与Python的尾递归蹦床 连载【5】​zhuanlan.zhihu.com
92b48ce06e68f4812db9561df533012e.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值