logseq_notes/pages/OJ notes/pages/Leetcode Rotting-Oranges.md
2023-06-14 14:27:22 +08:00

187 lines
3.7 KiB
Markdown

# Leetcode Rotting-Oranges
#### 2022-07-17 15:12
> ##### Algorithms:
>
> #algorithm #BFS
>
> ##### Data structures:
>
> #DS #vector_2d
>
> ##### Difficulty:
>
> #coding_problems #difficulty_medium
>
> ##### Additional tags:
>
> #leetcode
>
> ##### Revisions:
>
> N/A
##### Related topics:
##### Links:
- [Link to problem](https://leetcode.com/problems/rotting-oranges/)
***
### Problem
You are given an `m x n` `grid` where each cell can have one of three values:
- `0` representing an empty cell,
- `1` representing a fresh orange, or
- `2` representing a rotten orange.
Every minute, any fresh orange that is **4-directionally adjacent** to a rotten orange becomes rotten.
Return _the minimum number of minutes that must elapse until no cell has a fresh orange_. If _this is impossible, return_ `-1`.
#### Examples
**Example 1:**
![](https://assets.leetcode.com/uploads/2019/02/16/oranges.png)
```
**Input:** grid = [[2,1,1],[1,1,0],[0,1,1]]
**Output:** 4
```
**Example 2:**
```
**Input:** grid = [[2,1,1],[0,1,1],[1,0,1]]
**Output:** -1
```
**Explanation:** The orange in the bottom left corner (row 2, column 0) is never rotten, because rotting only happens 4-directionally.
**Example 3:**
```
**Input:** grid = [[0,2]]
**Output:** 0
```
**Explanation:** Since there are already no fresh oranges at minute 0, the answer is just 0.
#### Constraints
- `m == grid.length`
- `n == grid[i].length`
- `1 <= m, n <= 10`
- `grid[i][j]` is `0`, `1`, or `2`.
### Thoughts
> [!summary]
> This is a #BFS problem, because we use it to calculate
> the shortest {time, distance}
Be wary of these special cases:
- everything is empty cell -> return -1, no orange => no
fresh orange
- everything is rotten -> return 0
- everything is fresh -> return -1, impossible to rot
> [!tip] update the value in place vs. in queue
> Update in place, such as
>
> ```cpp
> if (grid[a + 1][b] != 0) {
> queue.push({a, b});
> grid[a + 1][b] = 0;
> }
> ```
>
> Can avoid multiple enqueues, because the value is already
> updated, so another node in queue can't push that again.
>
> ```cpp
> grid[a][b] = 0;
> if (grid[a + 1][b] != 0) {
> queue.push({a, b});
> }
> ```
>
> this code might result in pushing the same node twice.
### Solution
```cpp
class Solution {
public:
int orangesRotting(vector<vector<int>> &grid) {
// BFS
queue<pair<int, int>> todo;
int m = grid.size(), n = grid[0].size();
int time = -1;
bool isGridEmpty = true;
int freshCount = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 2) {
// add to queue, rotten
todo.push({i, j});
} else if (grid[i][j] == 1) {
freshCount++;
}
if (isGridEmpty && grid[i][j] != 0) {
isGridEmpty = false;
}
}
}
int x, y;
int offset[] = {-1, 1};
int newX, newY;
// if there is no value, there's no orange -> no fresh orange
if (isGridEmpty) {
return 0;
}
while (!todo.empty()) {
for (int i = 0, size = todo.size(); i < size; i++) {
x = todo.front().first;
y = todo.front().second;
todo.pop();
for (int o : offset) {
newX = x + o;
if (newX >= 0 && newX < m && grid[newX][y] == 1) {
todo.push({newX, y});
// cout<<"Pushed: "<<newX<<", "<<y<<'\n';
grid[newX][y] = 2;
freshCount--;
}
newY = y + o;
if (newY >= 0 && newY < n && grid[x][newY] == 1) {
todo.push({x, newY});
// cout<<"Pushed: "<<x<<", "<<newY<<'\n';
grid[x][newY] = 2;
freshCount--;
}
}
}
time++;
}
// check again if there is a fresh orange
if (freshCount != 0) {
return -1;
}
return time;
}
};
```