994. 腐烂的橘子 - 力扣(LeetCode)
题目要求:
在给定的 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
解法-1 双队列实现广度优先 O(N)
这是一道经典的广度优先遍历题,我们可以用两个队列q1和q2。
先遍历数组得到初始的所有腐烂的橘子的坐标,放到q1中,
然后对q1进行枚举,搜索队头坐标的上下左右坐标的橘子是不是好橘子,如果是就用infect函数"感染"这个橘子,并把它的坐标加入q2中,
最后如果q2为空说明没有再被"感染"的橘子了,退出循环;否则time++,然后把q1 = q2,q2置空,
最后遍历数组,如果有1,它就是永远不能感染的好橘子,返回-1;否则返回time。
class Solution {
void infect(vector<vector<int>>& grid,int j,int i)
{
if(j >= grid.size() || i >= grid[0].size())
{
return;
}
if(grid[j][i] == 1)
{
grid[j][i] = 2;
q2.push({j,i});
}
}
public:
int orangesRotting(vector<vector<int>>& grid) {
for(int i = 0;i < grid[0].size();i++)
{
for(int j = 0;j < grid.size();j++)
{
if(grid[j][i] == 2) // 初始的腐烂橘子
{
q1.push({j,i});
}
}
}
int time = 0;
while(!q1.empty())
{
while(!q1.empty())
{
int j = q1.front().first;
int i = q1.front().second;
q1.pop();
infect(grid,j+1,i);
infect(grid,j-1,i);
infect(grid,j,i+1);
infect(grid,j,i-1);
}
if(!q2.empty())
time++;
q1 = q2;
q2 = queue<pair<int,int>>();
}
// 找好橘子
for(int i = 0;i < grid[0].size();i++)
for(int j = 0;j < grid.size();j++)
{
if(grid[j][i] == 1)
return -1;
}
return time;
}
private:
queue<pair<int,int>> q1;
queue<pair<int,int>> q2;
};
优化:只使用一个队列
在遍历q1时,先得到q1的元素个数,循环就执行元素个数次即可:
class Solution {
void infect(vector<vector<int>>& grid,int j,int i)
{
if(j >= grid.size() || i >= grid[0].size())
{
return;
}
if(grid[j][i] == 1)
{
grid[j][i] = 2;
q.push({j,i});
}
}
public:
int orangesRotting(vector<vector<int>>& grid) {
for(int i = 0;i < grid[0].size();i++)
{
for(int j = 0;j < grid.size();j++)
{
if(grid[j][i] == 2) // 初始的腐烂橘子
{
q.push({j,i});
}
}
}
int time = 0;
while(!q.empty())
{
int size = q.size();
while(size--) // 执行当前元素个数次
{
int j = q.front().first;
int i = q.front().second;
q.pop();
infect(grid,j+1,i);
infect(grid,j-1,i);
infect(grid,j,i+1);
infect(grid,j,i-1);
}
if(q.size()>0)
time++;
}
for(int i = 0;i < grid[0].size();i++)
for(int j = 0;j < grid.size();j++)
{
if(grid[j][i] == 1)
return -1;
}
return time;
}
private:
queue<pair<int,int>> q;
};
内存优化:可以将调用infect函数改为使用4个if,节约空间
if((j+1 < grid.size() && i < grid[0].size()) && grid[j+1][i] == 1)
{
grid[j+1][i] = 2;
q.push({j+1,i});
}
if((j-1 < grid.size() && i < grid[0].size()) && grid[j-1][i] == 1)
{
grid[j-1][i] = 2;
q.push({j-1,i});
}
if((j < grid.size() && i+1 < grid[0].size()) && grid[j][i+1] == 1)
{
grid[j][i+1] = 2;
q.push({j,i+1});
}
if((j < grid.size() && i-1 < grid[0].size()) && grid[j][i-1] == 1)
{
grid[j][i-1] = 2;
q.push({j,i-1});
}