这是我参与「第四届青训营 」笔记创作活动的第[7]天
深度优先搜索(DFS)
- 深度优先搜索,检测DFS,最经典使用DFS解决的问题就是走迷宫。
- 从迷宫的一个点至另一个点,可以向上下左右四个方向走,首先随便根据一个路口走,如果遇到路口分支,那么根据默认的方向,也是起点第一步的方向走。假如这条路无法走通,那么回到另一个岔路口重新选择,当然 走过的路口是没有必要再走的,因为那条是死路,没有意义。直到最终找到出口,或者所有的路都走过了,则终止程序。
- 使用DFS找到的路径不一定是最短路径,但是是可通的路径。
动画演示
使用场景&算法思想
- 可以将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);
}
}
}
}