|
| 1 | +# Rotting Oranges |
| 2 | + |
| 3 | +You are given an m x n grid where each cell can have one of three values: |
| 4 | + |
| 5 | +- 0 representing an empty cell, |
| 6 | +- 1 representing a fresh orange, or |
| 7 | +- 2 representing a rotten orange. |
| 8 | + |
| 9 | +Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten. |
| 10 | + |
| 11 | +Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1. |
| 12 | + |
| 13 | +## Examples |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +Example 1 |
| 18 | +```text |
| 19 | +Input: grid = [[2,1,1],[1,1,0],[0,1,1]] |
| 20 | +Output: 4 |
| 21 | +``` |
| 22 | + |
| 23 | +Example 2: |
| 24 | +```text |
| 25 | +Input: grid = [[2,1,1],[0,1,1],[1,0,1]] |
| 26 | +Output: -1 |
| 27 | +Explanation: The orange in the bottom left corner (row 2, column 0) is never rotten, because rotting only happens 4-directionally. |
| 28 | +``` |
| 29 | + |
| 30 | +Example 3: |
| 31 | +```text |
| 32 | +Input: grid = [[0,2]] |
| 33 | +Output: 0 |
| 34 | +Explanation: Since there are already no fresh oranges at minute 0, the answer is just 0. |
| 35 | +``` |
| 36 | + |
| 37 | +## Constraints |
| 38 | + |
| 39 | +- m == grid.length |
| 40 | +- n == grid[i].length |
| 41 | +- 1 <= m, n <= 10 |
| 42 | +- `grid[i][j]` is 0, 1, or 2. |
| 43 | + |
| 44 | +## Topics |
| 45 | + |
| 46 | +- Array |
| 47 | +- Breadth-First Search |
| 48 | +- Matrix |
| 49 | + |
| 50 | +## Solution |
| 51 | + |
| 52 | +The algorithm uses BFS (Breadth-First Search) to simulate this minute-by-minute spreading process. It starts by finding |
| 53 | +all initially rotten oranges and counting all fresh oranges. Then it processes the rotting in rounds, where each round |
| 54 | +represents one minute. In each round, all currently rotten oranges spread the rot to their adjacent fresh oranges |
| 55 | +simultaneously. The process continues until either all fresh oranges have rotted (return the number of minutes elapsed) |
| 56 | +or no more fresh oranges can be reached (return -1). |
| 57 | + |
| 58 | +The key insight is to think of the rotting process as waves spreading outward from multiple sources simultaneously. |
| 59 | +Imagine dropping multiple stones into a pond at the same time - the ripples expand outward from each stone, and where |
| 60 | +they meet, they've both reached that point at the same time. |
| 61 | + |
| 62 | +In our problem, the rotten oranges are like those stones, and the rotting process spreads like ripples. Each "wave" or |
| 63 | +"ripple" represents one minute of time. All oranges at distance 1 from any rotten orange will rot after 1 minute, all |
| 64 | +oranges at distance 2 will rot after 2 minutes, and so on. |
| 65 | + |
| 66 | +This naturally leads us to BFS because: |
| 67 | + |
| 68 | +- BFS processes nodes level by level, which perfectly models the minute-by-minute spreading |
| 69 | +- We can start with all initially rotten oranges in our queue (multiple starting points) |
| 70 | +- Each level of BFS represents one unit of time |
| 71 | + |
| 72 | +The algorithm maintains a counter fresh_count for fresh oranges. As we process each level: |
| 73 | + |
| 74 | +- We rot all reachable fresh oranges at the current distance |
| 75 | +- We decrement fresh_count for each newly rotten orange |
| 76 | +- We track how many levels (minutes) we've processed |
| 77 | + |
| 78 | +The beauty of this approach is that BFS guarantees we're always rotting oranges in the optimal order - closest ones first. |
| 79 | +When fresh_count reaches 0, we know all fresh oranges have rotted, and the number of levels processed equals the minimum time |
| 80 | +needed. |
| 81 | + |
| 82 | +If after BFS completes, fresh_count > 0, it means some fresh oranges were unreachable (isolated), so we return -1. |
| 83 | + |
| 84 | +### Algorithm |
| 85 | + |
| 86 | +- Initial Setup and Counting First, we traverse the entire grid once to: |
| 87 | + - Find all initially rotten oranges (value 2) and add their coordinates (i, j) to a queue `queue` |
| 88 | + - Count all fresh oranges (value 1) and store in variable `fresh_count` |
| 89 | + - This preprocessing helps us know our starting points and when to stop |
| 90 | +- BFS Initialization |
| 91 | + - Initialize `minutes_elapsed = 0` to track the number of minutes elapsed |
| 92 | + - Define directions array dirs = (-1, 0, 1, 0, -1) for 4-directional movement |
| 93 | + - Using pairwise(directions) gives us [(-1, 0), (0, 1), (1, 0), (0, -1)] representing up, right, down, left |
| 94 | +- Level-by-Level BFS Processing The main BFS loop continues while `queue` is not empty AND `fresh_count` > 0: |
| 95 | + - Increment `minutes_elapsed` at the start of each level (representing one minute passing) |
| 96 | + - Process all oranges at the current level using `for _ in range(len(queue))`: |
| 97 | + - For each rotten orange (i, j), check all 4 adjacent cells |
| 98 | + - Calculate new coordinates: x, y = i + a, j + b |
| 99 | + - If the adjacent cell is within bounds and contains a fresh orange (`grid[x][y]` == 1): |
| 100 | + - Mark it as rotten: `grid[x][y]` = 2 |
| 101 | + - Add it to queue for next level: `queue.append((x, y))` |
| 102 | + - Decrement fresh count: `fresh_count -= 1` |
| 103 | + - Early termination: if `fresh_count == 0`, immediately return `minutes_elapsed` |
| 104 | +- Final Result After BFS completes: |
| 105 | + - If `fresh_count > 0`: Some fresh oranges couldn't be reached, return -1 |
| 106 | + - If `fresh_count == 0`: All fresh oranges have rotted, return 0 (or `minutes_elapsed` if terminated early) |
| 107 | + |
| 108 | +### Complexity Analysis |
| 109 | + |
| 110 | +#### Time Complexity O(m * n) |
| 111 | + |
| 112 | +The algorithm performs a BFS traversal starting from all initially rotten oranges. In the worst case, every cell in the |
| 113 | +grid needs to be visited exactly once. The initial scan to find all rotten oranges and count fresh oranges takes O(m × n) |
| 114 | +time. The BFS process visits each cell at most once, as each fresh orange becomes rotten exactly once and is added to the |
| 115 | +queue once. Therefore, the total time complexity is O(m × n). |
| 116 | + |
| 117 | +#### Space Complexity O(m * n) |
| 118 | + |
| 119 | +The space complexity is determined by the queue used for BFS. In the worst-case scenario, all oranges could be rotten |
| 120 | +initially (all cells contain 2), which means the queue would need to store all m × n positions at the start. Even in a |
| 121 | +more typical case where oranges rot progressively, the queue could potentially hold O(m × n) elements at any given time |
| 122 | +(for example, when a wave of rotting spreads across a large portion of the grid simultaneously). Therefore, the space |
| 123 | +complexity is O(m × n). |
| 124 | + |
0 commit comments