深度优先搜索(DFS) | 青训营笔记

161 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第[7]天

深度优先搜索(DFS)

  • 深度优先搜索,检测DFS,最经典使用DFS解决的问题就是走迷宫。
  • 从迷宫的一个点至另一个点,可以向上下左右四个方向走,首先随便根据一个路口走,如果遇到路口分支,那么根据默认的方向,也是起点第一步的方向走。假如这条路无法走通,那么回到另一个岔路口重新选择,当然 走过的路口是没有必要再走的,因为那条是死路,没有意义。直到最终找到出口,或者所有的路都走过了,则终止程序。
  • 使用DFS找到的路径不一定是最短路径,但是是可通的路径。

动画演示

13452330-7446a30e3ffecf88.gif

使用场景&算法思想

  • 可以将DFS抽象、可以用于
    • 排列
      • 给定一个字符串,将它所有的排列可能都计算出来。
    • n皇后
      • 在N×N格的棋盘上放置彼此不受攻击的N个皇后
    • 单词分割
      • 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
    • 自然数的拆分等等问题
      • 任何一个大于1的自然数N,总可以拆分成若干个小于N的自然数之和
  • DFS用的是一种著名的算法思想,回溯思想,如果这条路不可走,那么我就回到上一条路,非常适合使用递归来实现。

代码实现DFS

class Dfs{
   //存储图
   int[][] arr;
   //做过的点
   boolean[][] booarr;
   //四个方向
   int[][] dir = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
   //起点信息与终点信息
   int[][] st;

   private dfs(){}
   
   //0是可以通行的路 1是墙 不可通行
   public dfs(int[][] arr) {
      this.arr = arr;
      this.booarr = new boolean[arr.length][arr[0].length];
   }

   //主调用方法 需要传入起点与终点
   public boolean dfs(int i1, int j1, int i2, int j2) {
      this.st = new int[][]{{i1, j1}, {i2, j2}};
      if(more(i1, j1) || more(i2, j2)) {
         return false;
      }
      dfs(i1, j1);

      //最后返回终点是否走过即可
      return this.booarr[i2][j2];
   }

   private boolean more(int i, int j) {
      return i < 0 || i >= arr.length || j < 0 || j >= arr[0].length;
   }

   private void dfs(int x, int y) {
      //把走过的路给标记
      booarr[x][y] = true;
      //走到了终点就不必再走了
      if (x == st[1][0] && y == st[1][1]) {
         return;
      }
      //向4个方向走
      for (int i = 0; i < 4; i ++) {
         int x1 = x + dir[i][0];
         int y1 = y + dir[i][1];
         //如果x1 y1 合法的情况下 并且这条路没有走过并且可走,那么递归下去
         if (! more(x1, y1) && ! booarr[x1][y1] && arr[x1][y1] != 1) {
            dfs(x1, y1);
         }
      }
   }
}