1 前言
最近做到一道 找迷宫中从入口到出口最短路径的一道题。
力扣-找到离入口最近的出口
显然,理论上DFS和BFS都能找到解。
但是,DFS会超时,BFS就不会。
因此,我就又研究了一下DFS和BFS的原理,整理了一下他们的应用范围,希望自己能记住,刷题的时候少走弯路。
2 原理
2.1 BFS 宽度优先搜索算法(又称广度优先搜索)
形象地说:面临一个路口时,把所有的岔路口都记下来,然后选择其中一个进入,然后将它的分路情况记录下来,然后再返回来进入另外一个岔路
队列(queue)
实现:每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
结束条件:
- 找到所要找的元素时结束程序。 或者
- 如果遍历整个树还没有找到,结束程序。
性质:
- 新加入的结点到根的距离一定大于等于队列中排在它前面的结点。也就是说,BFS天然地带有路径长度的信息,可以依次搜索到走一步可到达的点,走两步可到达的点,走三步可到达的点…
- 搜索是以接近起始状态的程序依次扩展状态的
- 只对每个节点访问一遍
- BFS关键点是状态的选取和标记
2.2 DFS 深度优先搜索
形象地说:不管有多少条岔路,先一条路走到底,不成功就返回上一个路口然后就选择下一条岔路
栈(stack)
实现,整个过程可以想象成一个倒立的树形:
1、把根节点压入栈中。
2、每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。
结束条件:
- 找到所要找的元素时结束程序。
- 如果遍历整个树还没有找到,结束程序。
性质:
3. 搜索是以接近起始状态的程序依次扩展状态的
4. DFS的重要点在于状态回溯(树用DFS遍历时不需要回溯,因为每一个结点只能有唯一一条从上一个结点来的路径;图用DFS遍历时需要回溯,即再把visit[i]置为0,因为可能有多条从上一个结点的路径)
或者用 递归
来实现。
3 应用场景
3.1 BFS
- 找距离某一点的最短路,但路径不唯一,最先搜索到满足条件的就是最短的路径
- 大范围的查找
- 出现 “最短”、“最少”类似字眼的可以优先考虑
例题:
NOI-寻找尼莫
清华复试-玛雅人的密码
3.2 DFS
- 目的性强的查找与搜索问题,白话就是:能找出解就行
- 是否可达问题
例题:
NOI-算24点
NOI-碎纸机
北大复试-神器的口袋
回到开头的问题
为什么DFS会超时呢?
答:因为结束的条件和时间不同。BFS最先搜索到满足条件的就是最短的路径,所以可以直接return结果;DFS则需要遍历所有的可能情况,比较每一种情况是否是最短路径。