美文网首页
算法学习之闲话搜索

算法学习之闲话搜索

作者: 后厂村村长 | 来源:发表于2022-08-25 11:25 被阅读0次

    先来看一个问题:搜索的核心是什么?

    搜索的核心:就是暴力枚举所有可能!

    不会吧?!这么通俗,这么接地气?
    高端的食材往往只需要最朴素的烹饪方式!
    这就是搜索问题的核心,算法什么的,可以看作是对暴力枚举的辅助。

    搜索的常用算法:DFS(深度优先) 和 BFS(广度优先)

    DFS 和 BFS 是搜索的核心,贯穿始终。
    DFS 的概念源自图论,但搜索中的 DFS 和图论中的 DFS 有一些区别:搜索中的 DFS 一般指通过递归实现暴力枚举;如果不使用递归,也可使用栈来实现,但本质上是类似的。
    DFS:将状态空间映射成一张图,状态就是图中的节点,状态之间的联系就是图的边,然后在这张图上进行深度优先遍历;
    BFS:也是先影射成一张图:只不过遍历的策略变为了广度优先,一层层铺开遍历而已;
    所以 BFS 和 DFS 只是遍历这个状态图的两种方式罢了,关键在于如何构建状态图。

    注意事项:

    本质上,对上面所说的图进行遍历,最终会生成一颗搜索树。为了避免重复访问,需要记录已访问过的节点,这些是所有搜索算法的共有特性,需要牢记。
    另外,在树上遍历,不用担心是否有环,因为树的本质是一个简单无环图,记录已经访问的节点是为了减少时间复杂度,避免重复操作。

    DFS 算法流程

    • 1、首先将根节点入stack;
    • 2、从stack取出第一个节点,判断是否为target;如果找到,则结束搜寻并回传结果,否则将它的某一个尚未被检验的直接子节点入栈(BFS和DFS的基本区别就是此处的,子节点入栈方式)
    • 3、重复步骤 2。
    • 4、如果不存在未检测过的直接子节点(某个分支已遍历完成),则将上一级节点加入stack中,并重复步骤 2;
    • 5、重复步骤 4;
    • 6、若stack为空,表示整张图都检查过了,即图中为搜寻到target,结束并回传false;
      :这里的 stack 可理解为自实现的栈,也可以理解为调用栈

    DFS 遍历技巧

    DFS 常见的有三种方式:前序遍历、中序遍历、后序遍历;
    前中后序,对应的就是树的 左、根、右 节点;

    如何分辨该使用哪种遍历方式呢,其实并不难,因为大多数情况下,搜索过程中,当前节点的结果都需要依赖其他节点,因而诞生了这三种根据不同顺序遍历的方法。
    比如,当前节点需要依赖其子节点的计算结果,那么就需要考虑,使用后序遍历,自底向上,遍历了;
    反之,如果当前节点需要依赖其父节点的信息,那么就需要使用,前序遍历,自顶向下,遍历了。

    参考下图,DFS的深度优先遍历顺序是:A-》B-》E;


    DFS示例.png

    BFS 算法流程

    BFS 也是图论中算法的一种,不同于 DFS, BFS 采用的是横向搜索方式,辅助算法实现的数据结构通常采用队列结构,而DFS通常使用栈结构(见上面描述)。
    具体来说,我们不断从队头取出状态,然后将此状态对应的决策产生的所有新状态推入队尾,重复以上过程直至队列为空;

    • 1、首先将根节点放入队列中。
    • 2、从队列中取出第一个节点,并检验它是否为目标值:如果找到目标,则结束搜索并回传结果;否则将它所有尚未检验过的直接子节点加入队列。
    • 3、若队列为空,表示整张图都检查过了,即图中没有找到目标值。结束搜索并回传false。
    • 4、重复步骤 2。

    参考下图,BFS的广度优先遍历,会在每一层先遍历自己的同胞节点:


    BFS.png

    DFS 和 BFS 的使用区别

    一般情况,力扣中关于搜索的题目,首先考虑DFS,大部分时候可以解决;
    而BFS一般考虑用来处理最短路径问题,用一个哈希表 dist 记录从源点到图中其他点的距离;
    这个 dist 也可以充当防止环产生的功能,这是因为第一次到达一个点后,再次到达此点的距离,一定比第一次到达的路径大,利用此特点,就可知道是否是第一次访问了。

    DFS 和 BFS 的差异

    DFS 和 BFS 都是对题目设置的状态空间进行搜索但:

    • DFS 在分叉点会任选一条深入进入,即先挑自己的儿子节点搜索,遇到终点则返回,再次返回到分叉口(同胞节点)后,尝试下一个选择。基于此,我们可以在路径上记录一些数据;
    • BFS 在分叉点会选择将所有同胞节点的路径各尝试一次,因此需要使用队列来存储待处理的节点,队列中最多包含两层元素,且满足单调性,即相同层级(同胞节点)的元素在一起;

    村长总结

    总结一下搜索类题目的的常见解题套路:

    • 1、根据题目要求构建状态空间(画图);
    • 2、对图进行遍历(BFS 或者 DFS);
    • 3、记录和维护状态(比如 visited 维护访问情况, 队列和栈维护状态的决策方向等);

    几个小技巧:

    • DFS 通常都是有递推关系的,而递归关系就是图的边;梳理出递归关系后,就明白选择哪种遍历方式(前、中、后序遍历),更合理了;
    • BFS 由于其单调性,因此适合求解最短距离问题;
    • BFS 中用到的队列,不一定非得是队列结构,也可以用哈希表替代,比如村长用PHP刷题,而PHP是没有队列这种数据结构的,所以都是用数组类型模拟;
    • visitd(记录已访问节点) 和 dist/cost(记录距离花费等) 都可以起到记录节点访问情况的目的,以防止环的产生。

    。。。

    如果觉得本文对你有那么一丢丢的帮助,就抬起爪子点个赞吧!

    相关文章

      网友评论

          本文标题:算法学习之闲话搜索

          本文链接:https://www.haomeiwen.com/subject/vbgngrtx.html