刷到这道题的时候我心里还窃喜。这不就是典型的扩散题吗?BFS 直接秒了啊。结果啪啪打脸,连错两次,第三次才堪堪通过。说出来你们可能不信,错的地方全是我觉得 "根本不可能错" 的小细节。
题目一句话说清
给你一个 m x n 的网格,每个格子有三种状态:0 是空位,1 是新鲜橘子,2 是烂橘子。
每过一分钟,所有烂橘子都会把上下左右四个相邻的新鲜橘子也传染烂。问你最少需要多少分钟,能让所有橘子都烂掉。如果总有新鲜橘子躲在角落烂不了,就返回 -1。
我是怎么想到 BFS 的
其实这种 "一圈一圈往外扩散、每一步耗时相同、求最短时间" 的题,本能就该想到 BFS。DFS 是一条路走到黑,算不了这种 "同步推进" 的层序时间。
但这题有个小陷阱 ------ 它不是单一起点。一开始网格里可能有好多个烂橘子,它们是同时开始传染的。
我第一次写错,就是傻兮兮只拿第一个遇到的烂橘子当起点跑 BFS。结果算出来的时间直接偏大,完全不对。说白了这是道「多源 BFS」题,初始队列里得把所有一开始就烂掉的橘子都放进去。
真正的坑全在细节里
想通多源这个点之后,整体思路就很顺了:先扫一遍整个网格,数清楚有多少个新鲜橘子,同时把所有烂橘子的坐标都塞进队列。
如果新鲜橘子数一开始就是 0,直接返回 0 就行,不用白跑一趟。别笑,这个边界我第二次提交就忘了,直接喜提 WA。
接着就是层序遍历 BFS:每一轮只处理当前队列里所有的烂橘子 ------ 也就是这一分钟里会去传染别人的这批。挨个往四个方向走,遇到新鲜橘子就把它变烂,新鲜数减一,再放进队列里,下一轮它再去传染别人。每处理完一整层,时间就加 1 分钟。

等 BFS 跑完,看看剩下的新鲜橘子数是不是 0。是 0 就返回总时间,不是就说明有橘子永远感染不到,返回 - 1。
这里特意提一句,每次循环先存当前队列长度这个操作很关键。别问我怎么知道的,我一开始没按层来,每感染一个就给时间 + 1,结果分钟数算得乱七八糟,卡了好半天。
代码实现(JavaScript)
javascript
var orangesRotting = function(grid) {
const m = grid.length;
const n = grid[0].length;
const queue = [];
let freshCount = 0;
let minutes = 0;
// 上下左右四个方向,写数组遍历就不用写四遍if了
const dirs = [[-1,0],[1,0],[0,-1],[0,1]];
// 先扫一遍:统计新鲜橘子数量,所有烂橘子先入队
for(let i = 0; i < m; i++) {
for(let j = 0; j < n; j++) {
if(grid[i][j] === 1) {
freshCount++;
} else if(grid[i][j] === 2) {
queue.push([i, j]);
}
}
}
// 边界情况:一开始就没新鲜橘子,直接返回0
if(freshCount === 0) return 0;
while(queue.length) {
// 记录当前层的橘子数,这步千万别漏!漏了时间就算错了
const size = queue.length;
for(let i = 0; i < size; i++) {
const [x, y] = queue.shift();
// 四个方向挨个检查
for(const [dx, dy] of dirs) {
const nx = x + dx;
const ny = y + dy;
// 不越界 且 是新鲜橘子,才会被感染
if(nx >= 0 && nx < m && ny >=0 && ny < n && grid[nx][ny] === 1) {
grid[nx][ny] = 2; // 直接标记为烂橘子,省得重复入队
freshCount--;
queue.push([nx, ny]);
}
}
}
// 这一批全感染完了,过了一分钟
minutes++;
}
// 最后还有新鲜橘子就返回-1,否则返回时间
return freshCount === 0 ? minutes : -1;
};
对了,直接修改原网格当访问标记是很常用的技巧。当然你也可以额外开个 visited 数组,就是多占点空间,也能过。我是觉得反正题目没说不能改原数组,能省则省嘛。
复杂度分析
时间复杂度 O (mn),每个格子最多入队一次,不会重复处理。空间复杂度最坏 O (mn),比如一开局全是烂橘子,队列就装满了。
最后碎碎念
其实这题真的称不上难,就是 BFS 层序遍历的经典变种。但它特别考验你对边界的把控。
我自己踩过的坑给你们列一下,别再踩了:
- 只放一个烂橘子进队列,忘了是多源同时出发
- 没按层遍历,导致时间计算完全错误
- 漏掉 "一开始就没有新鲜橘子" 的边界情况
- 最后忘记检查剩余新鲜橘子,直接返回时间
说起来都是小问题,但真写起来很容易忽略。很多中等题都是这样,思路一眼就能看懂,提交就是过不了,全栽在细节里。
你刷这道题的时候是一次就过,还是也踩了坑?或者你有更巧妙的写法?评论区聊聊,我每条都会看。如果觉得这篇题解对你有帮助,点个赞让更多人看到就更好啦。