3568. Minimum Moves to Clean the Classroom
Problem Description
You have an m x n
grid representing a classroom where a student volunteer needs to clean up litter. The grid contains different types of cells:
'S'
: The student's starting position'L'
: Litter that needs to be collected (becomes empty after collection)'R'
: Reset area that restores the student's energy to full capacity (can be used multiple times)'X'
: Obstacle that blocks the student's path'.'
: Empty space the student can walk through
You're given an integer energy
representing the student's maximum energy capacity. The student starts at position 'S'
with full energy.
Movement rules:
- The student can move to adjacent cells (up, down, left, or right)
- Each move costs 1 unit of energy
- If energy reaches 0, the student can only continue moving if they're standing on a reset area
'R'
, which refills their energy to the maximum value
The goal is to find the minimum number of moves required for the student to collect all litter items in the classroom. If it's impossible to collect all litter, return -1
.
For example, if the student has 3 energy and there are 2 pieces of litter, they need to plan their path carefully to collect both pieces without running out of energy, potentially using reset areas strategically along the way.
Flowchart Walkthrough
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph?
- Yes: The classroom grid can be viewed as a graph where each cell is a node and adjacent cells (up, down, left, right) form edges. The student moves between these nodes/cells.
Is it a tree?
- No: The grid structure allows cycles - the student can revisit cells and take different paths to reach the same cell.
Is the problem related to directed acyclic graphs?
- No: The movement in the grid is bidirectional (can move back and forth between cells), and cycles are possible.
Is the problem related to shortest paths?
- Yes: We need to find the minimum number of moves (shortest path) to collect all litter items.
Is the graph Weighted?
- No: Each move costs exactly 1 unit (uniform weight). While energy is consumed, the actual path cost is measured in number of moves, not energy units.
BFS
- Yes: Since we have an unweighted graph shortest path problem, BFS is the appropriate algorithm.
Conclusion: The flowchart correctly leads us to use BFS (Breadth-First Search) for this problem. BFS is ideal here because:
- We're working with a grid graph structure
- We need to find the minimum number of moves (shortest path)
- All moves have equal cost (unweighted graph)
- We need to explore states level by level to ensure we find the optimal solution
The BFS implementation will track states that include position, energy level, and collected litter status to systematically explore all possible paths until all litter is collected.
Intuition
The key insight is that this isn't just a simple pathfinding problem - we need to track multiple dimensions of state as we explore the grid. Think of it like a delivery person who needs to collect multiple packages while managing their vehicle's fuel.
Why do we need more than just position tracking? Consider this scenario: the student might visit the same cell multiple times with different energy levels or different amounts of litter collected. For instance, they might pass through a cell early with high energy but no litter collected, then return later with low energy after collecting some litter. These are fundamentally different states even though the position is the same.
This leads us to define our state as a combination of four elements:
- Current position
(x, y)
- Current energy level
- Which litter items have been collected (tracked using a bitmask)
- The number of moves taken so far
The bitmask is particularly clever - if we have 3 pieces of litter, we can represent their collection status as a 3-bit number. 111
means all collected, 101
means first and third collected, etc. This allows us to efficiently track all possible combinations of collected litter.
Why BFS over DFS? Since we want the minimum number of moves, BFS naturally explores paths level by level, guaranteeing that the first time we collect all litter, we've done so in the minimum number of moves. DFS might find a solution but wouldn't guarantee it's optimal without exploring all possibilities.
The energy mechanic adds another layer - we can't just greedily collect the nearest litter. We might need to strategically visit reset areas 'R'
to refuel, even if it means taking a longer path. This is why we track energy as part of our state and allow revisiting cells with different energy levels.
The visited array vis[x][y][energy][mask]
prevents us from exploring the same state twice, which is crucial for efficiency. If we've already been at position (x, y)
with a certain energy level and collection status, there's no point exploring it again.
Learn more about Breadth-First Search patterns.
Solution Approach
The implementation uses BFS with state tracking to explore all possible paths until all litter is collected. Let's walk through the key components:
Initial Setup: First, we scan the grid to identify important information:
- Find the starting position
'S'
and store it as(x, y)
- Count total litter items and assign each a unique index in our bitmask
- Create a 2D array
d[i][j]
that maps each litter position to its bit index
State Representation:
Each state in our BFS consists of four components: (position_x, position_y, energy, mask)
- The
mask
is initialized as(1 << cnt) - 1
wherecnt
is the number of litter items - For example, with 3 litter items, the initial mask is
111
in binary (all bits set, meaning all litter needs to be collected)
Visited Array:
We use a 4D boolean array vis[x][y][energy][mask]
to track visited states:
- This prevents revisiting the same state (same position, energy, and collection status)
- The array dimensions are
m × n × (energy+1) × (2^cnt)
to cover all possible states
BFS Process: Starting from the initial state, we explore level by level:
-
Level-by-level exploration: Process all states at distance
ans
before moving to distanceans + 1
-
For each state in the current level:
- Check if
mask == 0
(all litter collected) - if yes, return current distance - Skip if energy is 0 (can't move)
- Try moving in all 4 directions (up, down, left, right)
- Check if
-
For each valid move:
- Check boundaries and obstacles (
'X'
) - Calculate new energy:
- If landing on
'R'
: reset to maximumenergy
- Otherwise: decrease by 1 (
cur_energy - 1
)
- If landing on
- Update mask if landing on litter
'L'
:- Use
nxt_mask &= ~(1 << d[x][y])
to clear the bit for collected litter
- Use
- Add new state to queue if not visited
- Check boundaries and obstacles (
Direction Array Pattern:
The code uses the pattern dirs = (-1, 0, 1, 0, -1)
for efficient direction iteration:
- For direction
k
, the offset is(dirs[k], dirs[k+1])
- This gives us: up
(-1,0)
, right(0,1)
, down(1,0)
, left(0,-1)
Termination:
- Success: When we find a state with
mask == 0
(all litter collected) - Failure: When the queue is empty and no solution found (return
-1
)
The algorithm guarantees the minimum number of moves because BFS explores states in order of increasing distance from the start.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Consider this 3x3 grid with energy = 2
:
S . L . R . L . .
Initial Setup:
- Starting position:
(0, 0)
where 'S' is located - Litter count: 2 pieces at positions
(0, 2)
and(2, 0)
- Assign bit indices: litter at
(0, 2)
gets bit 0, litter at(2, 0)
gets bit 1 - Initial mask:
11
in binary (both litter items need collection) - Initial state:
(0, 0, energy=2, mask=11)
BFS Exploration:
Level 0 (0 moves):
- Current state:
(0, 0, energy=2, mask=11)
- Mark as visited:
vis[0][0][2][11] = true
- Mask ≠ 0, so continue exploring
Level 1 (1 move):
From (0, 0, energy=2, mask=11)
, we can move:
- Right to
(0, 1)
: New state(0, 1, energy=1, mask=11)
- Down to
(1, 0)
: New state(1, 0, energy=1, mask=11)
Both states are added to queue and marked visited.
Level 2 (2 moves):
From (0, 1, energy=1, mask=11)
:
- Right to
(0, 2)
: Land on litter 'L'- Clear bit 0:
mask = 11 & ~(1 << 0) = 10
- New state:
(0, 2, energy=0, mask=10)
- Clear bit 0:
- Down to
(1, 1)
: Land on reset 'R'- Energy refills to 2
- New state:
(1, 1, energy=2, mask=11)
From (1, 0, energy=1, mask=11)
:
- Right to
(1, 1)
: Land on reset 'R'- New state:
(1, 1, energy=2, mask=11)
(already visited, skip)
- New state:
- Down to
(2, 0)
: Land on litter 'L'- Clear bit 1:
mask = 11 & ~(1 << 1) = 01
- New state:
(2, 0, energy=0, mask=01)
- Clear bit 1:
Level 3 (3 moves):
From (0, 2, energy=0, mask=10)
:
- Cannot move (energy = 0)
From (1, 1, energy=2, mask=11)
:
- Can move in all directions, exploring new states
From (2, 0, energy=0, mask=01)
:
- Cannot move (energy = 0)
Continuing the search...
After more exploration, we eventually find that the optimal path requires:
- Move right to
(0, 1)
- 1 move - Move down to
(1, 1)
(reset area) - 2 moves - Move down to
(2, 1)
- 3 moves - Move left to
(2, 0)
(collect litter) - 4 moves - Move right to
(2, 1)
- 5 moves - Move up to
(1, 1)
(reset area) - 6 moves - Move up to
(0, 1)
- 7 moves - Move right to
(0, 2)
(collect litter) - 8 moves
At this point, mask = 00
(all litter collected), so we return 8 moves.
The key insights from this example:
- We need to visit the reset area strategically to refuel
- The same cell
(1, 1)
is visited multiple times with different states - Energy management is crucial - we can't collect both litter items without refueling
- BFS ensures we find the minimum path by exploring all possibilities level by level
Solution Implementation
1class Solution:
2 def minMoves(self, classroom: List[str], energy: int) -> int:
3 # Get dimensions of the classroom
4 rows, cols = len(classroom), len(classroom[0])
5
6 # Create a 2D array to store lamp indices
7 lamp_indices = [[0] * cols for _ in range(rows)]
8
9 # Find starting position and count lamps
10 start_row = start_col = lamp_count = 0
11 for row_idx, row in enumerate(classroom):
12 for col_idx, cell in enumerate(row):
13 if cell == "S":
14 # Mark starting position
15 start_row, start_col = row_idx, col_idx
16 elif cell == "L":
17 # Assign index to each lamp
18 lamp_indices[row_idx][col_idx] = lamp_count
19 lamp_count += 1
20
21 # If no lamps to turn off, return 0
22 if lamp_count == 0:
23 return 0
24
25 # Create 4D visited array: [row][col][energy_level][lamp_state_mask]
26 visited = [
27 [[[False] * (1 << lamp_count) for _ in range(energy + 1)] for _ in range(cols)]
28 for _ in range(rows)
29 ]
30
31 # Initialize BFS queue with starting state
32 # (row, col, current_energy, lamp_mask) where lamp_mask has all lamps on (all bits set to 1)
33 queue = [(start_row, start_col, energy, (1 << lamp_count) - 1)]
34 visited[start_row][start_col][energy][(1 << lamp_count) - 1] = True
35
36 # Direction vectors for moving up, right, down, left
37 directions = (-1, 0, 1, 0, -1)
38
39 # Initialize move counter
40 moves = 0
41
42 # BFS to find minimum moves
43 while queue:
44 # Process all states at current level
45 current_level = queue
46 queue = []
47
48 for current_row, current_col, current_energy, lamp_mask in current_level:
49 # Check if all lamps are turned off
50 if lamp_mask == 0:
51 return moves
52
53 # Skip if no energy left
54 if current_energy <= 0:
55 continue
56
57 # Try moving in all 4 directions
58 for direction_idx in range(4):
59 next_row = current_row + directions[direction_idx]
60 next_col = current_col + directions[direction_idx + 1]
61
62 # Check if next position is valid and not a wall
63 if 0 <= next_row < rows and 0 <= next_col < cols and classroom[next_row][next_col] != "X":
64 # Calculate energy after move
65 # Restore to full energy if stepping on recharge station, otherwise decrease by 1
66 next_energy = (
67 energy if classroom[next_row][next_col] == "R" else current_energy - 1
68 )
69
70 # Update lamp mask if stepping on a lamp
71 next_lamp_mask = lamp_mask
72 if classroom[next_row][next_col] == "L":
73 # Turn off the lamp by clearing its bit
74 next_lamp_mask &= ~(1 << lamp_indices[next_row][next_col])
75
76 # Add to queue if this state hasn't been visited
77 if not visited[next_row][next_col][next_energy][next_lamp_mask]:
78 visited[next_row][next_col][next_energy][next_lamp_mask] = True
79 queue.append((next_row, next_col, next_energy, next_lamp_mask))
80
81 # Increment move counter after processing current level
82 moves += 1
83
84 # Return -1 if impossible to turn off all lamps
85 return -1
86
1class Solution {
2 public int minMoves(String[] classroom, int energy) {
3 int rows = classroom.length;
4 int cols = classroom[0].length();
5
6 // Store the index of each light in the grid
7 int[][] lightIndex = new int[rows][cols];
8 int startRow = 0, startCol = 0;
9 int lightCount = 0;
10
11 // Find start position and assign indices to lights
12 for (int i = 0; i < rows; i++) {
13 String row = classroom[i];
14 for (int j = 0; j < cols; j++) {
15 char cell = row.charAt(j);
16 if (cell == 'S') {
17 startRow = i;
18 startCol = j;
19 } else if (cell == 'L') {
20 lightIndex[i][j] = lightCount;
21 lightCount++;
22 }
23 }
24 }
25
26 // If no lights to turn off, return 0
27 if (lightCount == 0) {
28 return 0;
29 }
30
31 // 4D visited array: [row][col][energy][light_state_mask]
32 boolean[][][][] visited = new boolean[rows][cols][energy + 1][1 << lightCount];
33
34 // BFS queue storing states: [row, col, current_energy, lights_mask]
35 List<int[]> queue = new ArrayList<>();
36 int initialMask = (1 << lightCount) - 1; // All lights initially on
37 queue.add(new int[] {startRow, startCol, energy, initialMask});
38 visited[startRow][startCol][energy][initialMask] = true;
39
40 // Direction vectors for moving up, right, down, left
41 int[] directions = {-1, 0, 1, 0, -1};
42 int steps = 0;
43
44 // BFS to find minimum steps
45 while (!queue.isEmpty()) {
46 List<int[]> currentLevel = queue;
47 queue = new ArrayList<>();
48
49 for (int[] state : currentLevel) {
50 int currentRow = state[0];
51 int currentCol = state[1];
52 int currentEnergy = state[2];
53 int lightsMask = state[3];
54
55 // All lights turned off, return steps
56 if (lightsMask == 0) {
57 return steps;
58 }
59
60 // No energy left, skip this state
61 if (currentEnergy <= 0) {
62 continue;
63 }
64
65 // Try all 4 directions
66 for (int k = 0; k < 4; k++) {
67 int nextRow = currentRow + directions[k];
68 int nextCol = currentCol + directions[k + 1];
69
70 // Check if next position is valid and not a wall
71 if (nextRow >= 0 && nextRow < rows &&
72 nextCol >= 0 && nextCol < cols &&
73 classroom[nextRow].charAt(nextCol) != 'X') {
74
75 // Calculate next energy (recharge at 'R', otherwise decrease by 1)
76 int nextEnergy = classroom[nextRow].charAt(nextCol) == 'R'
77 ? energy
78 : currentEnergy - 1;
79
80 // Update lights mask if stepping on a light
81 int nextMask = lightsMask;
82 if (classroom[nextRow].charAt(nextCol) == 'L') {
83 // Turn off the light at this position
84 nextMask &= ~(1 << lightIndex[nextRow][nextCol]);
85 }
86
87 // Add to queue if this state hasn't been visited
88 if (!visited[nextRow][nextCol][nextEnergy][nextMask]) {
89 visited[nextRow][nextCol][nextEnergy][nextMask] = true;
90 queue.add(new int[] {nextRow, nextCol, nextEnergy, nextMask});
91 }
92 }
93 }
94 }
95 steps++;
96 }
97
98 // No solution found
99 return -1;
100 }
101}
102
1class Solution {
2public:
3 int minMoves(vector<string>& classroom, int energy) {
4 int rows = classroom.size();
5 int cols = classroom[0].size();
6
7 // Store the index of each light ('L') in the grid
8 vector<vector<int>> lightIndex(rows, vector<int>(cols, 0));
9 int startRow = 0, startCol = 0;
10 int lightCount = 0;
11
12 // Find starting position and count lights
13 for (int i = 0; i < rows; ++i) {
14 string& currentRow = classroom[i];
15 for (int j = 0; j < cols; ++j) {
16 char cell = currentRow[j];
17 if (cell == 'S') {
18 // Mark starting position
19 startRow = i;
20 startCol = j;
21 } else if (cell == 'L') {
22 // Assign index to each light
23 lightIndex[i][j] = lightCount;
24 lightCount++;
25 }
26 }
27 }
28
29 // If no lights to turn off, return 0
30 if (lightCount == 0) {
31 return 0;
32 }
33
34 // 4D visited array: [row][col][energy][light_mask]
35 // light_mask uses bits to represent which lights are still on
36 vector<vector<vector<vector<bool>>>> visited(rows,
37 vector<vector<vector<bool>>>(cols,
38 vector<vector<bool>>(energy + 1,
39 vector<bool>(1 << lightCount, false))));
40
41 // BFS queue: stores (row, col, current_energy, light_mask)
42 queue<tuple<int, int, int, int>> bfsQueue;
43
44 // Initial state: all lights are on (all bits set to 1)
45 int allLightsOn = (1 << lightCount) - 1;
46 bfsQueue.emplace(startRow, startCol, energy, allLightsOn);
47 visited[startRow][startCol][energy][allLightsOn] = true;
48
49 // Direction vectors for 4-directional movement (up, right, down, left)
50 vector<int> directions = {-1, 0, 1, 0, -1};
51
52 int moves = 0;
53
54 // BFS to find minimum moves
55 while (!bfsQueue.empty()) {
56 int levelSize = bfsQueue.size();
57
58 // Process all nodes at current level
59 while (levelSize--) {
60 auto [currentRow, currentCol, currentEnergy, lightMask] = bfsQueue.front();
61 bfsQueue.pop();
62
63 // Check if all lights are turned off
64 if (lightMask == 0) {
65 return moves;
66 }
67
68 // Skip if no energy left
69 if (currentEnergy <= 0) {
70 continue;
71 }
72
73 // Try all 4 directions
74 for (int dir = 0; dir < 4; ++dir) {
75 int nextRow = currentRow + directions[dir];
76 int nextCol = currentCol + directions[dir + 1];
77
78 // Check if next position is valid and not a wall
79 if (nextRow >= 0 && nextRow < rows &&
80 nextCol >= 0 && nextCol < cols &&
81 classroom[nextRow][nextCol] != 'X') {
82
83 // Calculate energy for next position
84 // Recharge stations ('R') restore energy to max
85 int nextEnergy = (classroom[nextRow][nextCol] == 'R') ?
86 energy : currentEnergy - 1;
87
88 // Update light mask if stepping on a light
89 int nextLightMask = lightMask;
90 if (classroom[nextRow][nextCol] == 'L') {
91 // Turn off the light at this position
92 nextLightMask &= ~(1 << lightIndex[nextRow][nextCol]);
93 }
94
95 // Add to queue if this state hasn't been visited
96 if (!visited[nextRow][nextCol][nextEnergy][nextLightMask]) {
97 visited[nextRow][nextCol][nextEnergy][nextLightMask] = true;
98 bfsQueue.emplace(nextRow, nextCol, nextEnergy, nextLightMask);
99 }
100 }
101 }
102 }
103 moves++;
104 }
105
106 // No solution found
107 return -1;
108 }
109};
110
1function minMoves(classroom: string[], energy: number): number {
2 const rows = classroom.length;
3 const cols = classroom[0].length;
4
5 // Store the index of each light ('L') in the grid
6 const lightIndex: number[][] = Array(rows).fill(0).map(() => Array(cols).fill(0));
7 let startRow = 0;
8 let startCol = 0;
9 let lightCount = 0;
10
11 // Find starting position and count lights
12 for (let i = 0; i < rows; i++) {
13 const currentRow = classroom[i];
14 for (let j = 0; j < cols; j++) {
15 const cell = currentRow[j];
16 if (cell === 'S') {
17 // Mark starting position
18 startRow = i;
19 startCol = j;
20 } else if (cell === 'L') {
21 // Assign index to each light
22 lightIndex[i][j] = lightCount;
23 lightCount++;
24 }
25 }
26 }
27
28 // If no lights to turn off, return 0
29 if (lightCount === 0) {
30 return 0;
31 }
32
33 // 4D visited array: [row][col][energy][lightMask]
34 // lightMask uses bits to represent which lights are still on
35 const visited: boolean[][][][] = Array(rows).fill(0).map(() =>
36 Array(cols).fill(0).map(() =>
37 Array(energy + 1).fill(0).map(() =>
38 Array(1 << lightCount).fill(false)
39 )
40 )
41 );
42
43 // BFS queue: stores [row, col, currentEnergy, lightMask]
44 const bfsQueue: [number, number, number, number][] = [];
45
46 // Initial state: all lights are on (all bits set to 1)
47 const allLightsOn = (1 << lightCount) - 1;
48 bfsQueue.push([startRow, startCol, energy, allLightsOn]);
49 visited[startRow][startCol][energy][allLightsOn] = true;
50
51 // Direction vectors for 4-directional movement (up, right, down, left)
52 const directions = [-1, 0, 1, 0, -1];
53
54 let moves = 0;
55
56 // BFS to find minimum moves
57 while (bfsQueue.length > 0) {
58 let levelSize = bfsQueue.length;
59
60 // Process all nodes at current level
61 while (levelSize-- > 0) {
62 const [currentRow, currentCol, currentEnergy, lightMask] = bfsQueue.shift()!;
63
64 // Check if all lights are turned off
65 if (lightMask === 0) {
66 return moves;
67 }
68
69 // Skip if no energy left
70 if (currentEnergy <= 0) {
71 continue;
72 }
73
74 // Try all 4 directions
75 for (let dir = 0; dir < 4; dir++) {
76 const nextRow = currentRow + directions[dir];
77 const nextCol = currentCol + directions[dir + 1];
78
79 // Check if next position is valid and not a wall
80 if (nextRow >= 0 && nextRow < rows &&
81 nextCol >= 0 && nextCol < cols &&
82 classroom[nextRow][nextCol] !== 'X') {
83
84 // Calculate energy for next position
85 // Recharge stations ('R') restore energy to max
86 const nextEnergy = (classroom[nextRow][nextCol] === 'R') ?
87 energy : currentEnergy - 1;
88
89 // Update light mask if stepping on a light
90 let nextLightMask = lightMask;
91 if (classroom[nextRow][nextCol] === 'L') {
92 // Turn off the light at this position
93 nextLightMask &= ~(1 << lightIndex[nextRow][nextCol]);
94 }
95
96 // Add to queue if this state hasn't been visited
97 if (!visited[nextRow][nextCol][nextEnergy][nextLightMask]) {
98 visited[nextRow][nextCol][nextEnergy][nextLightMask] = true;
99 bfsQueue.push([nextRow, nextCol, nextEnergy, nextLightMask]);
100 }
101 }
102 }
103 }
104 moves++;
105 }
106
107 // No solution found
108 return -1;
109}
110
Time and Space Complexity
Time Complexity: O(m × n × energy × 2^cnt)
The algorithm uses BFS with a 4-dimensional state space: position (i, j)
, current energy level, and a bitmask representing which litter cells ('L') have been collected. The visited array vis[x][y][energy][mask]
ensures each state is processed at most once. Since:
- There are
m × n
possible positions - Energy can range from
0
toenergy
(inclusive), givingenergy + 1
states - The bitmask has
2^cnt
possible values wherecnt
is the number of litter cells - Each state explores at most 4 directions
The total number of states that can be visited is m × n × (energy + 1) × 2^cnt
, and processing each state takes O(1)
time (checking 4 directions). Therefore, the overall time complexity is O(m × n × energy × 2^cnt)
.
Space Complexity: O(m × n × energy × 2^cnt)
The space is dominated by:
- The
vis
array which has dimensions[m][n][energy + 1][2^cnt]
, requiringO(m × n × (energy + 1) × 2^cnt)
space - The BFS queue
q
which in the worst case could contain all possible states, but this is bounded by the size of thevis
array - The
d
array which stores litter positions usesO(m × n)
space
Since the vis
array dominates, the overall space complexity is O(m × n × energy × 2^cnt)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Energy Management at Reset Areas
A critical pitfall is mishandling energy restoration when the student steps on a reset area 'R'
. Many implementations mistakenly restore energy only when the student has 0 energy, but the correct behavior is to always restore to full energy when stepping on 'R'
, regardless of current energy level.
Incorrect approach:
# Wrong: Only restore when energy is depleted if current_energy == 0 and classroom[next_row][next_col] == "R": next_energy = energy else: next_energy = current_energy - 1
Correct approach:
# Right: Always restore to full when stepping on 'R' next_energy = energy if classroom[next_row][next_col] == "R" else current_energy - 1
2. Allowing Movement with Zero Energy
Another common mistake is allowing the student to continue moving when energy reaches 0. The student should be unable to make any moves from a position with 0 energy unless they're currently standing on a reset area.
Incorrect approach:
# Wrong: Checking energy after attempting move for direction in directions: next_row, next_col = ... if current_energy == 0 and classroom[current_row][current_col] != "R": continue # This checks the wrong position
Correct approach:
# Right: Skip entire state if no energy to move if current_energy <= 0: continue # Skip processing this state entirely
3. Misunderstanding Litter Collection Timing
Some implementations incorrectly update the litter mask based on the current position at the start of each BFS iteration, rather than when stepping onto a litter cell. Litter should only be collected when the student moves onto a cell with litter.
Incorrect approach:
# Wrong: Collecting litter from current position each iteration for current_row, current_col, current_energy, lamp_mask in current_level: if classroom[current_row][current_col] == "L": lamp_mask &= ~(1 << lamp_indices[current_row][current_col])
Correct approach:
# Right: Collect litter only when moving onto it if classroom[next_row][next_col] == "L": next_lamp_mask &= ~(1 << lamp_indices[next_row][next_col])
4. Off-by-One Error in Visited Array Dimensions
The visited array must account for energy levels from 0 to energy
(inclusive), requiring energy + 1
slots. Missing the "+1" causes array index out of bounds errors.
Incorrect approach:
# Wrong: Missing the +1 for energy dimension
visited = [[[[False] * (1 << lamp_count) for _ in range(energy)]
for _ in range(cols)] for _ in range(rows)]
Correct approach:
# Right: Include energy level 0 through energy (energy + 1 total)
visited = [[[[False] * (1 << lamp_count) for _ in range(energy + 1)]
for _ in range(cols)] for _ in range(rows)]
5. Not Handling Edge Case of No Litter
If there's no litter in the classroom, the solution should immediately return 0 moves rather than proceeding with BFS, which would create invalid bitmask states.
Solution:
# Add this check after counting litter if lamp_count == 0: return 0
A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".
What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?
Recommended Readings
https assets algo monster cover_photos bfs svg Breadth First Search on Trees Hopefully by this time you've drunk enough DFS Kool Aid to understand its immense power and seen enough visualization to create a call stack in your mind Now let me introduce the companion spell Breadth First Search BFS
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!