LeetCode 994: Rotting Oranges
Solving LeetCode's Rotting Oranges problem in Kotlin, using Breadth-First Search (BFS) to efficiently simulate the rotting of oranges and determine the minimum time required.
The Rotting Oranges problem on LeetCode (LeetCode Link) presents a fascinating challenge involving simulating the spread of rotting oranges in a grid. You need to determine the minimum time it takes for all rotten oranges to rot and reach their neighbors. This blog post will walk through a Kotlin solution utilizing Breadth-First Search (BFS).
The Problem
You are given a 2D grid representing oranges where:
0: Represents an empty cell.1: Represents a fresh orange.2: Represents a rotten orange.
Oranges rot at time t. In one minute, each rotten orange will rot all its four neighboring oranges (up, down, left, right).
Return the minimum time required for all fresh oranges to rot. If it is impossible for all oranges to rot, return -1.
Example:
1
2
3
4
5
6
7
8
// Example:
// 2 1 1
// 1 1 0
// 0 1 1
val grid = arrayOf(intArrayOf(2, 1, 1), intArrayOf(1, 1, 0), intArrayOf(0, 1, 1))
println(LeetCode_994_Rotting_Oranges.orangesRotting(grid)) // Output: 2
Approach: Breadth-First Search (BFS)
The most suitable approach for this problem is Breadth-First Search (BFS). BFS systematically explores the grid layer by layer, ensuring that we process oranges closer to the source (rotten oranges) before those further away.
- Initialization: We start by initializing a queue (
q) with all rotten oranges and afreshOrangescounter to track the number of fresh oranges. - BFS Loop: We iterate as long as the queue is not empty:
- Process Current Level: We process all oranges at the current level (size of queue). For each rotten orange, we explore its four neighbors.
- Rot Neighbors: If a neighbor is a fresh orange (
grid[newR][newC] == 1), we mark it as rotten (grid[newR][newC] = 2), decrementfreshOranges, and add it to the queue. - Increment Time: If we processed any oranges in this level (meaning a rotten orange had neighbors to rot), we increment the
minutecounter.
- Check for Completion: After the BFS loop finishes, if
freshOrangesis 0, it means all oranges have rotted, and we return theminute. Otherwise, if there are still fresh oranges remaining, it means it’s impossible to rot all oranges, and we return -1.
The Code (Kotlin)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
object LeetCode_994_Rotting_Oranges {
fun orangesRotting(grid: Array<IntArray>): Int {
val q = LinkedList<Pair<Int, Int>>()
val rowSize = grid.size
val colSize = grid.first().size
var freshOranges = 0
// find all rotted oranges and add it to queue
for (row in 0..<rowSize) {
for (col in 0..<colSize) {
if (grid[row][col] == 2) {
q.offer(Pair(row, col))
}
else if (grid[row][col] == 1) {
freshOranges++
}
}
}
if(freshOranges == 0) return 0
var minute = 0
val directions = arrayOf(
intArrayOf(-1, 0), intArrayOf(1, 0),
intArrayOf(0, -1), intArrayOf(0, 1)
)
// Multi BFS
while (q.isNotEmpty()) {
val size = q.size // FREEZE the size for this minute level
var infectedThisRound = false
for (i in 0 until size) {
val (currR, currC) = q.poll()
for (d in directions) {
val newR = currR + d[0]
val newC = currC + d[1]
// Check bounds and if fresh
if (newR >= 0 && newR < rowSize &&
newC >= 0 && newC < colSize &&
grid[newR][newC] == 1) {
// Rot the orange
grid[newR][newC] = 2
freshOranges--
q.offer(Pair(newR, newC))
infectedThisRound = true
}
}
}
if (infectedThisRound) minute++
}
return if(freshOranges == 0) minute else -1
}
}
fun main() {
val grid = arrayOf(intArrayOf(2, 1, 1), intArrayOf(1, 1, 0), intArrayOf(0, 1, 1))
println(LeetCode_994_Rotting_Oranges.orangesRotting(grid))
}
Complexity Analysis
| Metric | Complexity | Explanation |
|---|---|---|
| Time | $O(M * N)$ | Where M is the number of rows and N is the number of columns in the grid. The BFS explores each cell at most once. |
| Space | $O(M * N)$ | In the worst case, the queue could contain all cells in the grid. This is because every cell can be a rotten orange and added to the queue. |
Source Code
🚀 Code: All the code for this tutorial is available in my DSA-Kotlin Repository.