描述
在给定的 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 。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j] 仅为 0、1 或 2
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/rotting-oranges
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
该题的主要思路是使用BFS(广度优先搜索)算法,将腐烂橘子的坐标加入队列中,然后遍历队列中的每个腐烂橘子,将其四周的新鲜橘子加入队列中,并将其标记为腐烂状态。每次遍历完当前时间点需要传染的所有橘子后,时间加1。直到队列为空,或者新鲜橘子的数量为0。
如果最终新鲜橘子的数量为0,则返回传染完成的时间;否则返回-1,表示有新鲜橘子没有被传染。
该算法的时间复杂度为O(nm),其中n和m分别为网格的行数和列数,空间复杂度为O(nm),即为队列的大小。
C++代码
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
// 定义四个方向,分别为“左, 上, 右, 下”
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
// 定义队列,存储腐烂橘子的坐标
queue<pair<int, int>> q;
// 统计新鲜橘子的数量
int fresh = 0;
// 获取网格的行数和列数
int n = grid.size(), m = grid[0].size();
// 遍历网格,将腐烂橘子的坐标加入队列中,并统计新鲜橘子的数量
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 2) {
q.push({i, j});
}
else if(grid[i][j] == 1) {
fresh++;
}
}
}
// 定义时间变量,记录腐烂的时间
int time = 0;
// 如果队列不为空,说明还有腐烂橘子没有传染完
while(!q.empty() && fresh>0) {
// 获取当前队列的长度,即为当前时间点需要传染的橘子个数
int size = q.size();
// 遍历当前时间点需要传染的所有橘子
for(int i = 0; i < size; i++) {
// 获取当前橘子的坐标
int x = q.front().first, y = q.front().second;
q.pop();
// 遍历当前橘子的四个方向
for(int j = 0; j < 4; j++) {
int nx = x + dx[j], ny = y + dy[j];
// 如果新的坐标越界或者对应的橘子已经腐烂或者为空,则跳过
if(nx < 0 || nx >= n || ny < 0 || ny >= m || grid[nx][ny] != 1) {
continue;
}
// 将新的橘子加入队列中,并将其标记为腐烂状态
q.push({nx, ny});
grid[nx][ny] = 2;
// 每传染一个新鲜橘子,将新鲜橘子的数量减1
fresh--;
}
}
// 时间加1
time++
}
return fresh > 0 ? -1 : time;
}
};