class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
int m = grid.size(); // 行数
int n = grid[0].size(); // 列数
int orange = 0; // 新鲜橘子的数量
int pre = 0; // 记录上一轮扩散前的新鲜橘子数量
int minute = 0; // 经过的分钟数
// 先统计一共有多少个新鲜橘子
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
orange++;
}
}
}
// 还有新鲜橘子,并且上一轮有新的橘子被腐烂
while (orange > 0 && orange != pre) {
// 保存这一轮扩散前的新鲜橘子数量
pre = orange;
// 遍历整个网格,寻找当前这一分钟应该扩散的腐烂橘子
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 2:初始腐烂
// 3:第1分钟腐烂
// 4:第2分钟腐烂......
if (grid[i][j] == minute + 2) {
// 下
if (i + 1 < m && grid[i + 1][j] == 1) {
grid[i + 1][j] = minute + 3; // 下一分钟腐烂
orange--;
}
// 上
if (i - 1 >= 0 && grid[i - 1][j] == 1) {
grid[i - 1][j] = minute + 3;
orange--;
}
// 左
if (j - 1 >= 0 && grid[i][j - 1] == 1) {
grid[i][j - 1] = minute + 3;
orange--;
}
// 右
if (j + 1 < n && grid[i][j + 1] == 1) {
grid[i][j + 1] = minute + 3;
orange--;
}
}
}
}
// 完成一轮扩散,时间 +1
minute++;
}
// 传播结束后还有新鲜橘子,说明这些橘子永远无法被腐烂
if (orange > 0) {
return -1;
}
// 所有新鲜橘子都已经腐烂
return minute;
}
};
总结
这道题的核心是 按分钟一层一层扩散。
这里用数字记录橘子的腐烂时间:
1 = 新鲜橘子
2 = 初始腐烂橘子
3 = 第1分钟腐烂
4 = 第2分钟腐烂
5 = 第3分钟腐烂
...
所以:
grid[i][j] == minute + 2
表示只让当前这一分钟应该扩散的腐烂橘子去感染上下左右的新鲜橘子。
两个变量重点记住:
orange:当前还剩多少新鲜橘子
pre:这一轮扩散开始前的新鲜橘子数量
如果最后:
orange > 0
说明传播已经停止,但还有新鲜橘子,因此:
return -1;
一句话记忆:
每分钟找到当前层的腐烂橘子,向上下左右传播;全部腐烂返回分钟数,有橘子永远感染不到就返回 -1。