994. 腐烂的橘子

中等 含交互动画

学完这道你应该能: 说清它为什么用「多源 BFS」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

网格里 2=烂、1=好、0=空。每分钟烂橘子让上下左右相邻的好橘子变烂。几分钟后全烂?

grid = 2,1,1 / 1,1,0 / 0,1,1
输出 = 4

思路解析

转折:普通 BFS 从一个点出发,这里腐烂是同时从多处发生的。所以把所有初始烂橘子一次性放进队列,再用 for _ in range(len(q)) 一次只处理「这一层」,每推进一整层就过去一分钟。开始前先数一遍好橘子 fresh,最后用它判断是否全烂。

第 0 分钟 · 标源 + 数 fresh:扫一遍:好橘子 fresh=6(绿),唯一的烂橘子 (0,0)(橙)入队,灰色 (1,2)、(2,0) 是空格。计时 0 分钟。

准备处理第 1 层 · 出队 (0,0):本层只有 (0,0)。看它上下左右:上、左越界,右 (0,1) 和下 (1,0) 是好橘子,要被传染。计时还停在 0——等这层邻居真的烂了,才算过去 1 分钟。

第 1 分钟 · 右/下变烂:(0,1)、(1,0) 变烂(高亮),fresh 6→4,它们入队等下一层。第 1 分钟结束。

第 2 分钟 · 这一层一起扩散:本层 (0,1)、(1,0) 同时传染各自的好邻居:(0,2) 和 (1,1) 变烂,fresh 4→2。

第 2 分钟 · 空格挡路(负例):负例:(1,1) 想往右传到 (1,2)、(1,0) 想往下传到 (2,0),但这两格是空格 0,腐烂传不过去,直接跳过。只有值为 1 的好橘子才会被传染。

第 3 分钟 · 绕过空格继续:第 3 分钟:(1,1) 往下把 (2,1) 传染变烂,fresh 2→1。

第 4 分钟 · 最后一个变烂:第 4 分钟:(2,1) 把最后的 (2,2) 传染,fresh 1→0。

检查 fresh==0 → 返回 4:队列空了,检查 fresh==0:全烂!返回 4 分钟。若还剩好橘子(被空格隔绝),就返回 -1。

以后你遇到「同时从多处扩散、求最短时间/距离」的题,就用多源 BFS:01 矩阵、地图分析都是它。

参考代码(Python)

Python
1q = deque()
2for 每个格子:
3    if 是烂橘子: q.append((i,j))   # 所有烂橘子一起入队
4    elif 是好橘子: fresh += 1
5while q and fresh > 0:
6    level += 1                     # 过去一分钟
7    for _ in range(len(q)):        # 只处理class="cl-str">"这一层"
8        i,j = q.popleft()
9        for 四个方向的好邻居:
10            变烂; fresh -= 1; q.append(邻居)
11return level if fresh == 0 else -1

复杂度分析

  • 时间复杂度:O(m×n) —— 每格进出队一次
  • 空间复杂度:O(m×n) —— 队列最多装一层

套路模板

记住骨架:所有起点一次性入队、for _ in range(len(q)) 锁层、每层 +1。01 矩阵、地图分析都是把多个源同时入队,和单源 BFS 只差「起点个数」。

Python
1# 「同时从多个源扩散、求最短时间/距离」都套
2q = deque(所有起点); seen = set(所有起点)
3level = 0
4while q:
5    for _ in range(len(q)):        # 锁定class="cl-str">"这一层"
6        x = q.popleft()
7        for y in 邻居(x):
8            if y not in seen: seen.add(y); q.append(y)
9    level += 1                     # 一层 = 一个时间单位

易错点

  • 错误写法:只把一个烂橘子入队正确写法:初始所有烂橘子都入队(它们是同时开始腐烂的)
  • 错误写法:不按层、直接数步数正确写法:for _ in range(len(q)) 锁定当前层(否则分不清「第几分钟」)
  • 错误写法:忘了判断剩余好橘子正确写法:最后 fresh>0 返回 -1(有的好橘子被空格隔绝,永远烂不了)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →207. 课程表 ← 返回题库