1. 题目
在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:
值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。
示例 1:
输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例 2:
输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个方向上。
示例 3:
输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。
2. 题解
java
class Solution {
public int orangesRotting(int[][] grid) {
int M = grid.length;
int N = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
int count = 0; // count 表示新鲜橘子的数量
for (int r = 0; r < M; r++) {
for (int c = 0; c < N; c++) {
if (grid[r][c] == 1) {
count++;
} else if (grid[r][c] == 2) {
queue.add(new int[]{r, c});
}
}
}
int round = 0; // round 表示腐烂的轮数,或者分钟数
while (count > 0 && !queue.isEmpty()) {
round++;
int n = queue.size();
for (int i = 0; i < n; i++) {
int[] orange = queue.poll();
int r = orange[0];
int c = orange[1];
if (r-1 >= 0 && grid[r-1][c] == 1) {
grid[r-1][c] = 2;
count--;
queue.add(new int[]{r-1, c});
}
if (r+1 < M && grid[r+1][c] == 1) {
grid[r+1][c] = 2;
count--;
queue.add(new int[]{r+1, c});
}
if (c-1 >= 0 && grid[r][c-1] == 1) {
grid[r][c-1] = 2;
count--;
queue.add(new int[]{r, c-1});
}
if (c+1 < N && grid[r][c+1] == 1) {
grid[r][c+1] = 2;
count--;
queue.add(new int[]{r, c+1});
}
}
}
if (count > 0) {
return -1;
} else {
return round;
}
}
}
3. 解析
出自:理清思路:为什么用 BFS,以及如何写 BFS 代码(Java/Python)
int M = grid.length; 和 int N = grid[0].length;: 这两个语句分别获取了二维数组grid的行数和列数,并将它们赋值给变量M和N。
Queue<int[]> queue = new LinkedList<>();: 创建一个队列来存储腐烂橙子的位置信息。
int count = 0; // count 表示新鲜橘子的数量: 初始化一个变量count,用于计算网格中剩余的新鲜橙子(值为1)的个数。
for (int r = 0; r < M; r++) {...}: 这段代码遍历网格中的每个单元格。如果该单元格包含新鲜橙子(值为1),则计数器加一;如果它包含腐烂的橙子(值为2),则将其位置信息添加到队列中。
int round = 0; // round 表示腐烂的轮数,或者分钟数: 初始化一个变量round,用于记录所需的时间或轮数。
while (count > 0 && !queue.isEmpty()) {...}: 这是主循环部分,它模拟了橙子腐烂的过程。只要网格中还有新鲜橙子(即count大于0)并且队列不为空,就会继续进行。
round++; int n = queue.size();: 在每一轮开始时,将round加一,并获取当前队列的大小n。这是因为需要处理上一轮中腐烂的橙子所引起的新一批新鲜橙子的位置信息。
for (int i = 0; i < n; i++) {...}: 这段代码遍历每一批新的腐烂橙子,并检查它们周围的位置(上、下、左、右)是否有新鲜橙子可以被吃掉。如果有,就将这些新鲜橙子标记为腐烂(即赋值为2),减少count计数器的值,并将其位置信息添加到队列中以便后续处理。
if (count > 0) {return -1;} else {return round;}: 如果在模拟过程中,网格中的新鲜橙子没有被清除(即count仍大于0),说明无法将所有的新鲜橙子变为腐烂。这种情况下,返回-1表示不可能;否则,返回round,即所需的最小时间或轮数。