题目描述
思路解析动画文字版
关键不是背模板,而是看懂为什么这题适合网格 DFS。
目标 · 被四面 X 围住的 O 才翻:被上下左右都是 X 围住的 O,要改成 X;而碰到边界、或和边界 O 连通的 O,要保留。例子里 (1,0)(1,1) 连到左边界要留,(1,3)(2,3) 被围要翻。
反向思路 · 从边界出发标「安全」:正面判断「某个 O 是否被围」要绕一圈很烦。反过来:只有和边界相连的 O 才安全。先从四条边上的 O 出发 DFS,把安全的标成 S,剩下没标的 O 必然被围。
从边界 O (1,0) 启动 DFS · 标 S:扫四条边,找到左边界上的 O (1,0)。从它 DFS,把它标成 S(安全)。
DFS 扩散 · (1,1) 连通也安全:(1,0) 的邻居 (1,1) 也是 O、连通,所以它也安全,标 S。这一片连到了边界,整片都保住。
内部 O 连不到边界 = 被围:再看 (1,3)(2,3) 这片 O:四周都是 X,DFS 从任何边界都到不了它们,没被标 S —— 它们就是被四面包围的,要翻。
第二遍 · 被围 O→X,安全 S→O:最后遍历整张 board:没标 S 的 O 改成 X(被围的 (1,3)(2,3)),标了 S 的恢复成 O(安全的 (1,0)(1,1))。
完成 · 原地改好:被围区域翻成 X、和边界相连的 O 全保留。核心就是「反着想」:与其判断谁被围,不如从边界标安全、剩下的就是被围。
把这句话记住,下次遇到同类题,就能更快选出方向。
边界三连:边界三连:极端输入先过一遍。
几个高频追问,记住答法。
参考代码
class Solution: def solve(self, board): m, n = len(board), len(board[0]) def dfs(r, c): if r<0 or r>=m or c<0 or c>=n or board[r][c] != 'O': return board[r][c] = 'S' # 标记安全(连到边界) dfs(r+1,c); dfs(r-1,c); dfs(r,c+1); dfs(r,c-1) for r in range(m): dfs(r,0); dfs(r,n-1) # 左右边界 for c in range(n): dfs(0,c); dfs(m-1,c) # 上下边界 for r in range(m): for c in range(n): board[r][c] = 'O' if board[r][c]=='S' else 'X'复杂度
- 时间复杂度:O(mn),每格最多被 DFS 访问一次 + 最后扫一遍
- 空间复杂度:O(mn),原地用 S 标记不开额外数组,只有 DFS 递归栈
可套用的代码模板
模板不是死背,而是提醒你写代码前先把状态、转移和边界排好。
Python
# 网格 DFS 通用检查表# 1. 定义状态/指针/容器# 2. 每轮只做一个清晰动作# 3. 更新答案并处理边界易错点
面试追问把动画讲成自己的话
追问为什么「反向从边界」更简单?
追问怎么区分安全和被围的 O?
追问复杂度?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
腐烂的橘子
LeetCode 994 · 中等 · 沿着 图 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题