
小小贪吃蛇,移动花样多。
平移加旋转,为把迷宫破。
代码复代码,bug 何其多。
六步化一步,AC 定我夺。
—— 1210. 穿过迷宫的最少移动次数
适用于需要计算连通块个数、大小的题目。
部分题目做法不止一种,也可以用 BFS 或并查集解决。
二叉树 DFS 与网格图 DFS 的区别:
| 二叉树 | 网格图 | |
|---|---|---|
| 递归入口 | 根节点 | 网格图的某个格子 |
| 递归方向 | 左儿子和右儿子 | 一般为左右上下的相邻格子 |
| 递归边界 | 空节点(或者叶节点) | 出界、遇到障碍或者已访问 |
模板(计算每个连通块的大小):
# 返回网格图 grid 每个连通块的大小
# 时间复杂度 O(mn)
def dfsGrid(grid: List[List[str]]) -> List[int]:
m, n = len(grid), len(grid[0])
vis = [[False] * n for _ in range(m)]
# 返回当前连通块的大小
def dfs(i: int, j: int) -> int:
vis[i][j] = True
size = 1
for x, y in (i, j - 1), (i, j + 1), (i - 1, j), (i + 1, j): # 左右上下
# 这里 grid[x][y] == '.' 根据题意修改
if 0 <= x < m and 0 <= y < n and grid[x][y] == '.' and not vis[x][y]:
size += dfs(x, y)
return size
comp_size = []
for i, row in enumerate(grid):
for j, ch in enumerate(row):
if ch != '.' or vis[i][j]: # ch != '.' 根据题意修改
continue
size = dfs(i, j)
comp_size.append(size)
return comp_size思维扩展:
适用于需要计算最短距离(最短路)的题目。
DFS 是不撞南墙不回头;BFS 是先访问近的,再访问远的。
模板(单源最短路):
# 返回从 (start_x, start_y) 出发,到其余格子的最短距离
# 时间复杂度 O(mn)
def bfsGrid(grid: List[List[str]], start_x: int, start_y: int) -> List[List[int]]:
m, n = len(grid), len(grid[0])
dis = [[-1] * n for _ in range(m)]
dis[start_x][start_y] = 0
q = deque([(start_x, start_y)])
while q:
i, j = q.popleft()
for x, y in (i, j - 1), (i, j + 1), (i - 1, j), (i + 1, j): # 左右上下
# 这里 grid[x][y] == '.' 根据题意修改
if 0 <= x < m and 0 <= y < n and grid[x][y] == '.' and dis[x][y] < 0:
dis[x][y] = dis[i][j] + 1
q.append((x, y))
return dis边权只有 和 的题目,也可以用 BFS 做。
见 图论题单 中的「§3.1 单源最短路:Dijkstra 算法」,我标记了网格图的题目。
欢迎在评论区发表你的思路。
如果你发现有题目可以补充进来,欢迎评论反馈。