notes/OJ notes/pages/Leetcode Rotting-Oranges.md
2022-09-06 20:22:48 +08:00

3.8 KiB

Leetcode Rotting-Oranges

2022-07-17 15:12

Algorithms:

#algorithm #BFS

Data structures:

#DS #vector_2d

Difficulty:

#coding_problem #difficulty_medium

Additional tags:

#leetcode

Revisions:

N/A


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:

**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

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.

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

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