# 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;
}
};
```
