剑指offer(七):深度优先搜索篇(python)

1. 迷宫问题

迷宫问题是典型的搜索问题,假设有下图所示的迷宫:

                                                                  

给定入口和出口,找到走出迷宫的路径(路径可能不止一条)。对于迷宫问题,先将迷宫数字化,用0表示可以通过的区域,用1表示墙,那么上面的迷宫可表示成下面的二维数组:

                                                 

左边的图是实际的迷宫图形,从入口到出口有两天路径,对应到右边的数字化的迷宫,也是有两条路径。接下来我们就通过右边的二维数组来搜索走出迷宫的路径 ,二维数组有17行18列,左上角的位置为(0,0),那么入口的位置为(16,0),而出口的位置为(0,17),路径是由一组位置坐标对组成。

1.1 深度优先搜索(DFS)

深度优先搜索算法(Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。DFS具体实现:随机选择一条路径搜索,并将搜索过的路径标识,如果遇到“死胡同”且没有找到目标项,那么原路返回到某“十字路口”(回溯)换一条路径进行搜索,直到搜索到目标项,若所有路径都进行了搜索依然没有找到目标项,那么说明目标项不在图中。深度优先搜索可以通过递归或堆栈实现,它的搜索路径不一定为最优的,但是它可以得到所有可行的路径。为了方便理解深度优先搜索,给出了下图中点亮迷宫中所有灯的小例子:

             

在树结构中的前序遍历、中序遍历以及后序遍历都属于深度优先搜索。接下来是迷宫问题的DFS的实现方式。DFS可以用两种方式实现:递归和堆栈。具体代码实现如下:

               

深度优先搜索是按照一条路径搜索到底,直到这条路径走不通,然后回溯到某个“十字路口”对其他路径进行搜索,如果这条路径恰好是需要的路径,那么会返回这条路径。在这道迷宫的题目中,有两条路径可以走出迷宫,最终结果是那条路径,这取决于在初始化函数中的self.dirs是怎样的,如果self.dirs中的(-1,0)即向上是第一个元素的话,那么在两条路径的交汇口处,会优先搜索上边的路径,因为上边存在走出迷宫的路径,所以最终返回位置序列是红线路径;相反如果self.dirs中的(0,1)即向右是第一个元素的话,那么在交汇口出会优先搜索右边的路径,同样的右边也存在走出迷宫的路径,最终返回的位置序列是蓝线路径。

1.2 广度优先搜索(BFS)

广度优先搜索算法(Breadth-First-Search,BFS) 也是一种图形搜索算法,树是特殊化的图结构,广度优先搜索实际上相当于树中的层序遍历。随机选择一个节点作为初始节点,初始点入队列,初始点出队,检验是否为目标项,若是结束搜索并返回初始点,若不是,将初始点存入链表中,且将初始点相连的所有节点入队,节点分别出队检验,若当前出队节点为目标项结束搜索并返回,否则将与其相连的节点入队,并将该节点存入链表,循环的对所有节点做相同操作直到队列为空还没有找到目标项,说明目标项不在图中。广度优先搜索主要借助队列实现,若图的所有边的长度相等,BFS可以得到最优值。有关广度优先搜索的图解如下:                                                                                                                                                                                                          

可以看到,广度优先搜索并不是沿着一条路径搜索,而是把所有的节点周围所有路径都进行搜索在进入下一阶段,搜索路径有些类似于往水中扔一块石头形成的水波一层层外扩 。

迷宫问题的BFS实现方式的代码如下:

        

测试函数和DFS的相同,所以没有再次给出。这里用到了字典,建立当前位置和下一位置之间的关系,作用等同于哈希表。 

 

2. 华容道问题

有1到8八个数字,放在3x3的九宫格里面,那么将会留下一个空格,如下图:

                                                                 

空格可以和上下左右的数字交换,可以认为空格是可以移动的。如果移动成下图的样子:

                                                                  

则移动成功。给定九宫格数字摆放的初始状态,返回是否可以移动成下图的样子,若能,则给出空格移动的路径。代码实现见下图:

     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值