深度优先搜索DFS_图文详解_Java代码_leetcode刷题模板

深度优先搜索DFS_图文详解_Java代码_leetcode刷题模板

    • 一、参考链接
    • 二、图文讲解
    • 三、总结

一、参考链接

-注 本文仅用于个人学习,侵权删。

  • 1、基础讲解
    • 搜索思想——DFS & BFS(基础基础篇)
    • 数据结构:图的遍历–深度优先、广度优先
  • 2、套路模板
    • ①深度优先搜索模板(LeetCode)
      • 两种实现 DFS 的方法。第一种方法是进行递归,这一点你可能已经很熟悉了。这里我们提供了一个模板作为参考:
      • 当我们递归地实现 DFS 时,似乎不需要使用任何栈。但实际上,我们使用的是由系统提供的隐式栈,也称为调用栈(Call Stack)
      • DFS - 模板 I
        /*
         * Return true if there is a path from cur to target.
         */
        boolean DFS(Node cur, Node target, Set<Node> visited) {
            return true if cur is target;
            for (next : each neighbor of cur) {
                if (next is not in visited) {
                    add next to visted;
                    return true if DFS(next, target, visited) == true;
                }
            }
            return false;
        }
        
    • 递归解决方案的优点是它更容易实现。 但是,存在一个很大的缺点:如果递归的深度太高,你将遭受堆栈溢出。 在这种情况下,您可能会希望使用 BFS,或使用显式栈实现 DFS。
    • DFS - 模板 II
      /*
       * Return true if there is a path from cur to target.
       */
       boolean DFS(int root, int target) {
          Set<Node> visited;
          Stack<Node> s;
          add root to s;
          while (s is not empty) {
              Node cur = the top element in s;
              return true if cur is target;
              for (Node next : the neighbors of cur) {
                  if (next is not in visited) {
                      add next to s;
                      add next to visited;
                  }
              }
              remove cur from s;
          }
          return false;
      }
      
    • ② 回溯算法解题套路框架(labuladong的算法小抄):详情见第二节

二、图文讲解

  • 回溯算法解题套路框架
  • DFS 算法就是回溯算法 ,废话不多说,直接上回溯算法框架。解决一个回溯问题,实际上就是一个决策树的遍历过程。你只需要思考 3 个问题:
    • 1、路径:也就是已经做出的选择。
    • 2、选择列表:也就是你当前可以做的选择。
    • 3、结束条件:也就是到达决策树底层,无法再做选择的条件。
  • 回溯算法框架
    result = []
    def backtrack(路径, 选择列表):
        if 满足结束条件:
            result.add(路径)
            return
    
        for 选择 in 选择列表:
            做选择
            backtrack(路径, 选择列表)
            撤销选择
    
    • 核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。

三、总结

  • 回溯算法就是个多叉树的遍历问题,关键就是在前序遍历和后序遍历的位置做一些操作,算法框架如下:
    def backtrack(...):
        for 选择 in 选择列表:
            做选择
            backtrack(...)
            撤销选择
    
  • 写 backtrack 函数时,需要维护走过的「路径」和当前可以做的「选择列表」,当触发「结束条件」时,将「路径」记入结果集。
  • 其实想想看,回溯算法和动态规划是不是有点像呢?我们在动态规划系列文章中多次强调,动态规划的三个需要明确的点就是「状态」「选择」和「base case」,是不是就对应着走过的「路径」,当前的「选择列表」和「结束条件」?
  • 某种程度上说,**动态规划的暴力求解阶段就是回溯算法。**只是有的问题具有重叠子问题性质,可以用 dp table 或者备忘录优化,将递归树大幅剪枝,这就变成了动态规划。而今天的两个问题,都没有重叠子问题,也就是回溯算法问题了,复杂度非常高是不可避免的。

你可能感兴趣的:(#,BFS&DFS,数据结构与算法)