994. 腐烂的橘子
在给定的网格中,每个单元格可以有以下三个值之一:
- 值
0
代表空单元格;- 值
1
代表新鲜橘子;- 值
2
代表腐烂的橘子。每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。
返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回
-1
。
示例 1:
输入:[[2,1,1],[1,1,0],[0,1,1]] 输出:4
示例 2:
输入:[[2,1,1],[0,1,1],[1,0,1]] 输出:-1 解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。
示例 3:
输入:[[0,2]] 输出:0 解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。
提示:
1 <= grid.length <= 10
1 <= grid[0].length <= 10
grid[i][j]
仅为0
、1
或2
解法一
//时间复杂度O(n), 空间复杂度O(n)
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
int minutes = -1, count = 0;
int m = grid.size(), n = grid[0].size();
queue<pair<int, int>> q1;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == 2) q1.push({i, j});
else if(grid[i][j] == 1) count++;
}
}
if(count == 0) return 0;
while(!q1.empty()) {
queue<pair<int, int>> q2;
q2.swap(q1);
while(!q2.empty()) {
int x = q2.front().first, y = q2.front().second;
q2.pop();
if(x > 0 && grid[x - 1][y] == 1) {
grid[x - 1][y] = 2;
count--;
q1.push({x - 1, y});
}
if(x < m - 1 && grid[x + 1][y] == 1) {
grid[x + 1][y] = 2;
count--;
q1.push({x + 1, y});
}
if(y > 0 && grid[x][y - 1] == 1) {
grid[x][y - 1] = 2;
count--;
q1.push({x, y - 1});
}
if(y < n - 1 && grid[x][y + 1] == 1) {
grid[x][y + 1] = 2;
count--;
q1.push({x, y + 1});
}
}
minutes++;
}
return count == 0 ? minutes : -1;
}
};
优化版:
//时间复杂度O(n), 空间复杂度O(n)
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
int minutes = -1, count = 0;
int m = grid.size(), n = grid[0].size();
const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1};
queue<pair<int, int>> q1;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == 2) q1.push({i, j});
else if(grid[i][j] == 1) count++;
}
}
if(count == 0) return 0;
while(!q1.empty()) {
queue<pair<int, int>> q2;
q2.swap(q1);
while(!q2.empty()) {
pair<int, int> pos = q2.front();
q2.pop();
for(int i = 0; i < 4; i++) {
int x = pos.first + dx[i];
int y = pos.second + dy[i];
if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) {
grid[x][y] = 2;
count--;
q1.push({x, y});
}
}
}
minutes++;
}
return count == 0 ? minutes : -1;
}
};
思路:
图的层序遍历。具体做法是使用两个队列q1和q2,q1记录上(下)一层的结点,q2记录当前层的结点。minutes记录经历的分钟数(深度)。
- 首先遍历所有元素,将坏橘子(值为2)的坐标入队q1,同时记下好橘子(值为1)的数量count;
- 从q1记录的坏橘子坐标开始,进行层序遍历。在每一层内,将q1元素转移至q2(swap)。对于遍历的每一个元素,判断其上、下、左、右是否有好橘子(值为1),若有就将其感染(令值为2),同时对计数count--,并将新感染的橘子入队q1。
- 循环步骤2,在每一层内对时间minutes++,直到q1为空。
- 最后判断好橘子是否有剩余(count == 0),若有就返回-1,否则返回minutes。
第一版本的代码分支条件太多,优化版使用了循环,效率可能会更好一些。
2019/08/25 13:51