语言运行泰博那契数列_算法小专栏开篇:DFS之Fibonaci数列

778b0efcc581b3b339f2fac5e04fb5da.gif

从今天开始会给大家介绍一些我在学习软件算法时期的一些题目或者笔记总结,本身我也不是计软班科的,也不是打ACM的,所以也不要指望我来给你讲解Leetcode或者Linkcode了,遇到Hard题在下实在也是爱莫能助。

9a5e7c357aeff34c771263ee98104148.png

初衷更多是为了 简单的算法知识普及 吧,也是我当初做笔记的一个想法,后面出个 小专栏 也行。 相信大家也关注了其他大佬的号,有很多讲得666的文章和视频, B站 更是比比皆是,我当然会以我自己的理解来写, 不求卓越,但求无误。

4e946013a0e8aea2a661062058b49f2d.gif

一些关于计算机专业术语的词我会比较少用,采用一些直观的数据来体现~ 今天从 DFS(深度优先搜索) 开始,一开始学的时候老师给了道测试题,我直接懵了,DFS?可能大计基的时候或者学C语言的时候讲过,简单的结构还是会的。后面开始去刷题,啊嘞?年轻人 不讲code德,各种剪枝优化,各种记忆法,各种退出条件,咳咳咳……( 吐血ing01 Brief Introduction to DFS 但是现在来看其实DFS其是 以套路为先,判断逻辑为主,剪枝优化为辅 的一种算法思路。 好啦,我们来大概介绍一下, 深度优先搜索DFS广度优先搜索BFS 是两种很重要的软件算法,在 图论 里面有很多应用,像 最短路径全局查找 等优化问题。 深度优先,即是在当前既定的搜索策略下不断进行下去, 一条路走到黑 。可以这么说, 如果行不通了,退出当前的循环,改变搜索策略,继续循环往复,直到找到出口 ,是不是很像小白鼠走迷宫。

1a42b64426963a478f79852d5b75fcb7.png

意思很好懂,我认为有 关键三个点
  1. 第一个是搜索策略,这是核心算法,自不用多说

  1. 第二个是循环的前后参量传递,即我走过的路我不走了,或者通过一条失败的路pass掉其他n条类似的路直接不走,节省时间空间,其中一些变量的传递。

  1. 第三个是退出条件,没有退出条件,就是无限循环,Happy Ending!

上面的 Key Point 会在以后的内容里在逐步体现~ 大家也不用有太多心里负担,就当小百科。02 Fibonaci and DFS Implementation

今天我还是从Fibonaci(斐波那契数列)开始,给大家介绍DFS。

所用环境是  Windows10+Python3.7。

语法都是很简单的,本身就是解释性语言,通俗易懂。 斐波那契数列很常见:1,1,2,3,5,…… 从第三项开始,每一项都是前两项的和。假设我要求第n项,我是不是要知道第n-1项和第n-2项,要求第n-1项,又要知道第n-2项和第n-3项,以此类推,就是一个不断循环的过程,啥时候是个头呢? 我们知道第一项和第二项都是1,那当递归到这两项时,直接返回1便可以了。就好像在一个迷宫,每一层有一个房间,每一层的房间里有打开上一层需要的钥匙,最上面一层的房间有奥利奥,怎么吃到奥力给呢?

d47062c06b7e6c2a15b019aa2f421681.gif

直观思路:你只需要走到最低的一层,拿到最低两层的钥匙,便可以一直往上走,期间不断开门,收集钥匙,直到打开最上面一层的房间。

来看看code:

    
def fibonaci():
    """
    Function: get n_th value in Fibonacci_array using DFS
    Returns: None
    """
    import time
    # input the index
    n=int(input())
    # core function
    def dfs(x):
        if x==1 or x==2:
            return 1
        else:
            # recursion step
            return dfs(x-1)+dfs(x-2)
    # record processing time
    start=time.time()
    # print answer
    print(dfs(n))
    print("Using {:.5f} s".format(time.time()-start))
    return

>>> fibonaci()
20
6765
Using 0.01405 s
>>> fibonaci()
35
9227465
Using 2.22722 s
上面便是按照我们的思路写出的DFS求解第n项斐波那契数列的函数,其中time库是为了计算程序执行的时间, 核心函数的思路便是当递归到第一项或者第二项直接返回1,否则通过函数递归求解对应前两项的值 。 但是当n太大的时候,你会发现很慢出结果。求解 第35项用了2.22秒,简直不能忍。 原因是,每求一个第n项,我们都必须求到0~n-1项,而且这个过程在子过程里,即求第n-1项的时候也是一样,算法的时间复杂度随着N的增大呈现指数增长, 时间的复杂度为O(2^n) ,即2的n次方,算法进行的过程 形象上说可以看成是在遍历一棵 二叉树

80648690b7d74ec90cb6b2fca496e92d.png

03 Memory Search in DFS 改进方法有很多,比如 化为矩阵乘法并应用快速幂运算等,还有记忆化搜索 。 记忆化搜索是DFS常用的一种优化剪枝策略,剪枝这里的意思就很形象了,就是把没必要的节点给去掉,不去递归到那里。 我们可以容易知道,求解第n项和第n-1项在上面的函数里的过程基本上是一样的,也就是说程序做了很多无用功,要是我们 在求解过程中把中间的过程记录下来,如果再次需要到该值直接调用,就可以提高效率,即用空间换时间

说干就干!

b4ad28883fe764af651916380291f2e9.gif

def fibonaci():
    """
    Function: get n_th value in Fibonacci Array using DFS with memory search
    Returns: None
    """
    import time
    # input the index
    n=int(input())
    # store intermediate results
    ans=[False for i in range(n+1)]
    # core function
    def dfs(x):
        nonlocal ans
        if ans[x]:
            return ans[x]
        if x==1 or x==2:
            ans[x]=1
            return 1
        else:
            ans[x]=dfs(x-1)+dfs(x-2)
            return ans[x]
    # record processing time
    start=time.time()
    # print answer
    print(dfs(n))
    print("Using {:.5f} s".format(time.time()-start))
    return

>>> fibonaci()
35
9227465
Using 0.00751 s
>>> fibonaci()
50
12586269025
Using 0.00795 s
>>> fibonaci()
100
354224848179261915075
Using 0.01003 s

可以看到记忆化搜索的方法在求解第35项时只用了0.01153,实际上的时间复杂度基本维持在线性 O(N) 的级别,nice!

20e0c499b7fc43089ab0f99bc74237c4.png

04 Little Trick 实际上用递归的方法会受到 函数递归栈数量 的限制,默认是1000,可以 采用非递归的形式求解 ,但是不在今天的范围,就不做介绍,大家可以自行查阅相关资料喔~ 另外有个小技巧,在有些时候确实是需要求解斐波那契数列第n项,但是n的不是太大(less than 50),那可以用下面这种 较快的 lambda匿名函数 方式,简洁~
# Lambda function definition
Fibo=lambda x: 1 if x==1 or x==2 else Fibo(x-1)+Fibo(x-2)
# test
>>> Fibo(20)
6765
>>> Fibo(35)
9227465
其实就是把非记忆化搜索的DFS核心函数简化为匿名函数,这一点在以后的某些题目里会经常使用,个人觉得还是比较方便的。

今天就先到这啦,有问题意见的仔仔可以公众号提问,会及时回复哒!

427fd875b1911689af67cf49a37cfdd9.gif

快来和小刀一起秃头吧

c5b2662e4642db7973ed3c829504e348.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值