1、什么是深度优先搜索(DFS)
深度优先搜索用的是回溯思想,这种思想解决问题的过程,非常适合用递归来实现;换句话说,DFS 是借助栈来实现的。
举个栗子,假设你站在迷宫的某个岔路口,然后想找到出口。你随意选择一个岔路口来走,走着走着发现走不通的时候,你就回退到上一个岔路口,重新选择一条路继续走,直到最终找到出口。这种走法就是一种深度优先搜索策略。
2、代码模板
递归写法
visited = set()
def dfs(node, visited):
if node in visited:
return
visited.add(node)
# process current node here
process(node)
for next_node in node.children():
if not next_node in visited:
dfs(next node, visited)
非递归写法
def dfs(self, tree):
if tree.root is None:
return []
visited, stack = [], tree.root
while stack:
node = stack.pop()
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
stack.push(nodes)
# other processing work
...
3、实战
3.1、统计封闭岛屿的数目
class Solution {
private int[][] coords = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public int closedIsland(int[][] grid) {
if (grid == null || grid.length < 3 || grid[0].length) {
return 0;
}
int res = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j <grid[0].length; j++) {
if (grid[i][j] == 0 && dfs(grid, i, j)) {
res++;
}
}
}
return res;
}
public boolean dfs(int[][] grid, int i, int j) {
// 当 i, j 超过数组 index 范围时,返回 false
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length) {
return false;
}
// 遇到 1 说明被水域包围,返回 true
if (grid[i][j] == 1) {
return true;
}
// 将访问过得标记为 1,可以避免重复访问,计算的问题
grid[i][j] = 1;
boolean flag = true;
// 校验四周是否都被水域包围,如果都被包围,则 flag 为 true
for (int[] coord : coords) {
flag = flag & dfs(grid, i + coord[0], j + coord[1]);
}
return flag;
}
}
4、小结
DFS 通俗的理解就是,地毯式层层推进,从起始点开始,依次向外遍历。广度优先搜索和深度优先搜索是图上的两种最常用、最基本的搜索算法。