Facebook Pixel

3568. Minimum Moves to Clean the Classroom

MediumBit ManipulationBreadth-First SearchArrayHash TableMatrix
Leetcode Link

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:

  1. We're working with a grid graph structure
  2. We need to find the minimum number of moves (shortest path)
  3. All moves have equal cost (unweighted graph)
  4. 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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Current position (x, y)
  2. Current energy level
  3. Which litter items have been collected (tracked using a bitmask)
  4. 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 where cnt 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:

  1. Level-by-level exploration: Process all states at distance ans before moving to distance ans + 1

  2. 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)
  3. For each valid move:

    • Check boundaries and obstacles ('X')
    • Calculate new energy:
      • If landing on 'R': reset to maximum energy
      • Otherwise: decrease by 1 (cur_energy - 1)
    • Update mask if landing on litter 'L':
      • Use nxt_mask &= ~(1 << d[x][y]) to clear the bit for collected litter
    • Add new state to queue if not visited

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 Evaluator

Example 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)
  • 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)
  • Down to (2, 0): Land on litter 'L'
    • Clear bit 1: mask = 11 & ~(1 << 1) = 01
    • New state: (2, 0, energy=0, mask=01)

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:

  1. Move right to (0, 1) - 1 move
  2. Move down to (1, 1) (reset area) - 2 moves
  3. Move down to (2, 1) - 3 moves
  4. Move left to (2, 0) (collect litter) - 4 moves
  5. Move right to (2, 1) - 5 moves
  6. Move up to (1, 1) (reset area) - 6 moves
  7. Move up to (0, 1) - 7 moves
  8. 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 to energy (inclusive), giving energy + 1 states
  • The bitmask has 2^cnt possible values where cnt 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], requiring O(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 the vis array
  • The d array which stores litter positions uses O(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
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More