Facebook Pixel

499. The Maze III πŸ”’

Problem Description

This problem involves a ball rolling through a maze. The maze is represented as a 2D grid where:

  • 0 represents an empty space
  • 1 represents a wall
  • The borders of the maze are all walls

The ball has special movement rules:

  1. When the ball starts rolling in a direction (up, down, left, or right), it keeps rolling until it hits a wall
  2. The ball cannot stop in the middle of its path - it must roll until blocked by a wall
  3. Once the ball stops at a wall, it can choose a new direction to roll (but must be different from the last direction)
  4. There's a hole in the maze - if the ball rolls over the hole, it drops in and stops

Given:

  • A maze (2D grid)
  • Starting position of the ball [ball_row, ball_col]
  • Position of the hole [hole_row, hole_col]

You need to find the shortest path for the ball to reach the hole, where distance is measured by the number of empty spaces traveled (excluding the start position but including the hole position).

The answer should be:

  • A string of directional instructions using characters: 'u' (up), 'd' (down), 'l' (left), 'r' (right)
  • If multiple paths have the same shortest distance, return the lexicographically smallest one (e.g., "dlr" comes before "drl")
  • If it's impossible for the ball to reach the hole, return "impossible"

For example, if the ball needs to roll down, then left, then right to reach the hole with the shortest distance, the answer would be "dlr".

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 maze can be viewed as a graph where each empty cell is a node, and edges exist between cells that the ball can roll between. The ball's rolling behavior creates directed edges in this graph.

Is it a tree?

  • No: The maze graph contains cycles - the ball can potentially return to previously visited positions by taking different paths, so it's not a tree structure.

Is the problem related to directed acyclic graphs?

  • No: The maze graph can have cycles as the ball can revisit positions through different rolling paths.

Is the problem related to shortest paths?

  • Yes: We need to find the shortest distance (minimum number of empty spaces traveled) for the ball to reach the hole.

Is the graph weighted?

  • Yes: Each roll has a weight equal to the number of empty spaces the ball travels. Different directions from the same position can result in different distances (weights).

Dijkstra's Algorithm

  • Yes: Since we have a weighted graph and need the shortest path, Dijkstra's algorithm is appropriate. However, the solution uses a modified BFS/DFS approach that tracks distances similar to Dijkstra's.

Additional Consideration for DFS: While the flowchart leads us to Dijkstra's algorithm, the solution actually uses a BFS approach with distance tracking. However, DFS with backtracking could also work here because:

  • We need to explore all possible paths to find the shortest one
  • We need to track the lexicographically smallest path when distances are equal
  • The constraints allow for exploring multiple paths systematically

Conclusion: The flowchart suggests using Dijkstra's Algorithm for this weighted shortest path problem. The actual solution implements a BFS variant that maintains distance and path information, effectively achieving the same goal as Dijkstra's while also handling the lexicographic ordering requirement.

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

Intuition

The key insight is that this problem combines shortest path finding with special movement mechanics. Unlike typical maze problems where you move one step at a time, here the ball rolls continuously until it hits a wall. This means each "move" can cover multiple cells, and the distance traveled varies based on the direction chosen.

Think of it like rolling a marble on a tilted board - once it starts moving, it won't stop until something blocks it. This changes our graph structure: instead of edges connecting adjacent cells, we have edges connecting "stopping positions" (cells next to walls) with weights equal to the distance rolled.

Since we need the shortest path in a weighted graph, we naturally think of Dijkstra's algorithm or BFS with distance tracking. However, there's an additional twist - when multiple paths have the same distance, we need the lexicographically smallest one. This means we can't just stop at the first valid path we find.

The solution uses a modified BFS approach where:

  1. We track the minimum distance to reach each position using a dist matrix
  2. We also track the path taken to reach each position using a path matrix
  3. When we find a position reachable with the same distance but a lexicographically smaller path, we update it

The rolling mechanics are handled in the inner while loop - for each direction, we keep moving the ball until it either hits a wall or reaches the hole. The distance increases by 1 for each empty space traveled.

The clever part is the update condition: dist[x][y] > step or (dist[x][y] == step and path[i][j] + d < path[x][y]). This ensures we update a position if:

  • We found a shorter path to it, OR
  • We found an equal-length path that's lexicographically smaller

By processing positions level by level (BFS style) and maintaining both distance and path information, we guarantee finding the shortest path that's also lexicographically minimal when ties occur.

Solution Approach

The implementation uses BFS with distance and path tracking to handle both the shortest distance requirement and lexicographic ordering.

Data Structures:

  1. deque for BFS queue - stores positions (i, j) that the ball can stop at
  2. dist matrix - tracks minimum distance to reach each position (initialized to infinity)
  3. path matrix - stores the string of directions taken to reach each position

Algorithm Steps:

  1. Initialization:

    • Set starting position's distance to 0 and path to empty string ''
    • Add starting position to queue
  2. BFS Processing: For each position (i, j) dequeued:

    • Try all four directions: up (-1, 0, 'u'), down (1, 0, 'd'), left (0, -1, 'l'), right (0, 1, 'r')
  3. Rolling Simulation: For each direction (a, b, d):

    while (0 <= x + a < m and 0 <= y + b < n and maze[x + a][y + b] == 0 and (x != rh or y != ch)):
        x, y = x + a, y + b
        step += 1

    This loop simulates the ball rolling:

    • Continues while next position is within bounds, is empty (0), and current position isn't the hole
    • Increments position and step count for each space traveled
    • Stops when hitting a wall or reaching the hole
  4. Path Update Logic:

    if dist[x][y] > step or (dist[x][y] == step and path[i][j] + d < path[x][y]):

    Updates the position if:

    • Found a shorter path (dist[x][y] > step)
    • Found equal-length path that's lexicographically smaller (path[i][j] + d < path[x][y])
  5. Queue Management: Only add the new position to queue if it's not the hole:

    if x != rh or y != ch:
        q.append((x, y))

    This prevents further exploration from the hole position.

  6. Result: Return path[rh][ch] if it exists (ball reached the hole), otherwise return 'impossible'

The key insight is that BFS naturally explores positions in increasing order of moves made, and by maintaining both distance and path information, we can ensure we get the shortest path that's also lexicographically minimal when multiple shortest paths exist.

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.

Example maze:

maze = [[0, 0, 0, 0, 0],
        [1, 1, 0, 0, 1],
        [0, 0, 0, 0, 0],
        [0, 1, 0, 0, 1],
        [0, 1, 0, 0, 0]]

ball = [4, 3]  # Starting position
hole = [0, 1]  # Hole position

Step 1: Initialization

  • Set dist[4][3] = 0 and path[4][3] = ""
  • Add (4, 3) to the queue

Step 2: Process position (4, 3)

Try rolling in each direction from (4, 3):

  • Up ('u'): Roll from (4,3) β†’ (3,3) β†’ stops at (2,3) due to wall at (1,3)

    • Distance: 2 spaces
    • Update: dist[2][3] = 2, path[2][3] = "u"
    • Add (2,3) to queue
  • Down ('d'): Can't move (already at bottom edge)

  • Left ('l'): Roll from (4,3) β†’ (4,2) β†’ stops at (4,1) due to wall at (4,0)

    • Distance: 2 spaces
    • Update: dist[4][1] = 2, path[4][1] = "l"
    • Add (4,1) to queue
  • Right ('r'): Roll from (4,3) β†’ stops at (4,4) due to edge

    • Distance: 1 space
    • Update: dist[4][4] = 1, path[4][4] = "r"
    • Add (4,4) to queue

Step 3: Process position (4, 4) (shortest distance so far = 1)

  • Up ('u'): Roll from (4,4) β†’ (3,4) β†’ (2,4) β†’ (1,4) β†’ stops at (0,4) due to edge

    • Distance: 1 + 4 = 5 spaces
    • Update: dist[0][4] = 5, path[0][4] = "ru"
    • Add (0,4) to queue
  • Left ('l'): Roll from (4,4) β†’ (4,3) β†’ (4,2) β†’ stops at (4,1) due to wall

    • Distance: 1 + 3 = 4 spaces
    • Current dist[4][1] = 2 < 4, so no update

Step 4: Process position (4, 1) (distance = 2)

  • Up ('u'): Roll from (4,1) β†’ (3,1) β†’ (2,1) β†’ (1,1) β†’ stops at (0,1) - THE HOLE!
    • Distance: 2 + 4 = 6 spaces
    • Update: dist[0][1] = 6, path[0][1] = "lu"
    • Don't add to queue (it's the hole)

Step 5: Process position (2, 3) (distance = 2)

  • Left ('l'): Roll from (2,3) β†’ (2,2) β†’ (2,1) β†’ (2,0)

    • Distance: 2 + 3 = 5 spaces
    • Update: dist[2][0] = 5, path[2][0] = "ul"
    • Add (2,0) to queue
  • Up ('u'): Roll from (2,3) β†’ (1,3) β†’ stops at (0,3) due to edge

    • Distance: 2 + 2 = 4 spaces
    • Update: dist[0][3] = 4, path[0][3] = "uu"
    • Add (0,3) to queue

Step 6: Continue processing...

After processing position (0,3) with distance 4:

  • Left ('l'): Roll from (0,3) β†’ (0,2) β†’ stops at (0,1) - THE HOLE!
    • Distance: 4 + 2 = 6 spaces
    • Current dist[0][1] = 6 (same distance)
    • Compare paths: "lu" vs "uul"
    • "lu" < "uul" lexicographically, so no update

Final Result: The ball reaches the hole at (0,1) with:

  • Shortest distance: 6 spaces
  • Path: "lu" (left from start, then up to hole)

This is returned as the answer since it's both the shortest path and lexicographically smallest among paths of the same length.

Solution Implementation

1class Solution:
2    def findShortestWay(
3        self, maze: List[List[int]], ball: List[int], hole: List[int]
4    ) -> str:
5        """
6        Find the shortest path for a ball to reach a hole in a maze.
7        The ball rolls until it hits a wall or falls into the hole.
8      
9        Args:
10            maze: 2D grid where 0 = empty, 1 = wall
11            ball: Starting position [row, col]
12            hole: Target position [row, col]
13      
14        Returns:
15            String representing the shortest path (lexicographically smallest if tie)
16            or 'impossible' if no path exists
17        """
18        from collections import deque
19        from math import inf
20        from typing import List
21      
22        # Get maze dimensions
23        rows, cols = len(maze), len(maze[0])
24      
25        # Extract starting position and hole position
26        start_row, start_col = ball
27        hole_row, hole_col = hole
28      
29        # Initialize BFS queue with starting position
30        queue = deque([(start_row, start_col)])
31      
32        # Initialize distance matrix with infinity
33        distances = [[inf] * cols for _ in range(rows)]
34        distances[start_row][start_col] = 0
35      
36        # Initialize path matrix to track the path to each position
37        paths = [[None] * cols for _ in range(rows)]
38        paths[start_row][start_col] = ''
39      
40        # BFS to find shortest path
41        while queue:
42            current_row, current_col = queue.popleft()
43          
44            # Try all four directions: up, down, left, right
45            directions = [
46                (-1, 0, 'u'),  # up
47                (1, 0, 'd'),   # down
48                (0, -1, 'l'),  # left
49                (0, 1, 'r')    # right
50            ]
51          
52            for row_delta, col_delta, direction_char in directions:
53                # Initialize position and step count for rolling
54                next_row, next_col = current_row, current_col
55                steps = distances[current_row][current_col]
56              
57                # Keep rolling in the current direction until hitting a wall or falling into hole
58                while (
59                    0 <= next_row + row_delta < rows
60                    and 0 <= next_col + col_delta < cols
61                    and maze[next_row + row_delta][next_col + col_delta] == 0
62                    and (next_row != hole_row or next_col != hole_col)
63                ):
64                    next_row += row_delta
65                    next_col += col_delta
66                    steps += 1
67              
68                # Update if we found a shorter path or same length but lexicographically smaller
69                if distances[next_row][next_col] > steps or (
70                    distances[next_row][next_col] == steps 
71                    and paths[current_row][current_col] + direction_char < paths[next_row][next_col]
72                ):
73                    distances[next_row][next_col] = steps
74                    paths[next_row][next_col] = paths[current_row][current_col] + direction_char
75                  
76                    # Add to queue if not at hole (we can't roll from the hole)
77                    if next_row != hole_row or next_col != hole_col:
78                        queue.append((next_row, next_col))
79      
80        # Return the path to hole or 'impossible' if no path exists
81        return paths[hole_row][hole_col] or 'impossible'
82
1class Solution {
2    public String findShortestWay(int[][] maze, int[] ball, int[] hole) {
3        // Get maze dimensions
4        int rows = maze.length;
5        int cols = maze[0].length;
6      
7        // Extract starting position (ball) and target position (hole)
8        int ballRow = ball[0], ballCol = ball[1];
9        int holeRow = hole[0], holeCol = hole[1];
10      
11        // Initialize BFS queue with starting position
12        Deque<int[]> queue = new LinkedList<>();
13        queue.offer(new int[] {ballRow, ballCol});
14      
15        // Initialize distance matrix to track shortest distance to each cell
16        int[][] distance = new int[rows][cols];
17        for (int i = 0; i < rows; i++) {
18            Arrays.fill(distance[i], Integer.MAX_VALUE);
19        }
20        distance[ballRow][ballCol] = 0;
21      
22        // Initialize path matrix to track the path string to reach each cell
23        String[][] paths = new String[rows][cols];
24        paths[ballRow][ballCol] = "";
25      
26        // Define four directions: up, down, left, right with their corresponding characters
27        int[][] directions = {
28            {-1, 0, 'u'},  // up
29            {1, 0, 'd'},   // down
30            {0, -1, 'l'},  // left
31            {0, 1, 'r'}    // right
32        };
33      
34        // BFS to find shortest path
35        while (!queue.isEmpty()) {
36            int[] current = queue.poll();
37            int currentRow = current[0];
38            int currentCol = current[1];
39          
40            // Try rolling the ball in each direction
41            for (int[] direction : directions) {
42                int deltaRow = direction[0];
43                int deltaCol = direction[1];
44                String directionChar = String.valueOf((char) direction[2]);
45              
46                // Initialize new position and step counter
47                int newRow = currentRow;
48                int newCol = currentCol;
49                int steps = distance[currentRow][currentCol];
50              
51                // Keep rolling the ball until it hits a wall or falls into the hole
52                while (newRow + deltaRow >= 0 && newRow + deltaRow < rows && 
53                       newCol + deltaCol >= 0 && newCol + deltaCol < cols && 
54                       maze[newRow + deltaRow][newCol + deltaCol] == 0 &&
55                       (newRow != holeRow || newCol != holeCol)) {
56                    newRow += deltaRow;
57                    newCol += deltaCol;
58                    steps++;
59                }
60              
61                // Update if we found a shorter path or a lexicographically smaller path with same distance
62                if (distance[newRow][newCol] > steps ||
63                    (distance[newRow][newCol] == steps && 
64                     (paths[currentRow][currentCol] + directionChar).compareTo(paths[newRow][newCol]) < 0)) {
65                  
66                    // Update distance and path
67                    distance[newRow][newCol] = steps;
68                    paths[newRow][newCol] = paths[currentRow][currentCol] + directionChar;
69                  
70                    // Add to queue only if not at the hole (hole is the destination)
71                    if (newRow != holeRow || newCol != holeCol) {
72                        queue.offer(new int[] {newRow, newCol});
73                    }
74                }
75            }
76        }
77      
78        // Return the path to hole, or "impossible" if no path exists
79        return paths[holeRow][holeCol] == null ? "impossible" : paths[holeRow][holeCol];
80    }
81}
82
1class Solution {
2public:
3    string findShortestWay(vector<vector<int>>& maze, vector<int>& ball, vector<int>& hole) {
4        // Get maze dimensions
5        int rows = maze.size();
6        int cols = maze[0].size();
7      
8        // Starting position (ball) and target position (hole)
9        int startRow = ball[0], startCol = ball[1];
10        int holeRow = hole[0], holeCol = hole[1];
11      
12        // BFS queue to explore positions
13        queue<pair<int, int>> bfsQueue;
14        bfsQueue.push({startRow, startCol});
15      
16        // Distance matrix to track minimum steps to reach each position
17        vector<vector<int>> distance(rows, vector<int>(cols, INT_MAX));
18        distance[startRow][startCol] = 0;
19      
20        // Path matrix to track the direction sequence to reach each position
21        vector<vector<string>> paths(rows, vector<string>(cols, ""));
22      
23        // Direction vectors: up, down, left, right with their corresponding characters
24        vector<vector<int>> directions = {
25            {-1, 0, 'u'},  // up
26            {1, 0, 'd'},   // down
27            {0, -1, 'l'},  // left
28            {0, 1, 'r'}    // right
29        };
30      
31        // BFS to find shortest path
32        while (!bfsQueue.empty()) {
33            auto currentPos = bfsQueue.front();
34            bfsQueue.pop();
35          
36            int currentRow = currentPos.first;
37            int currentCol = currentPos.second;
38          
39            // Try rolling the ball in each direction
40            for (auto& direction : directions) {
41                int deltaRow = direction[0];
42                int deltaCol = direction[1];
43                char directionChar = (char)direction[2];
44              
45                // Roll the ball until it hits a wall or falls into the hole
46                int newRow = currentRow;
47                int newCol = currentCol;
48                int steps = distance[currentRow][currentCol];
49              
50                // Keep rolling while:
51                // 1. Next position is within bounds
52                // 2. Next position is not a wall (maze value is 0)
53                // 3. Current position is not the hole
54                while (newRow + deltaRow >= 0 && newRow + deltaRow < rows && 
55                       newCol + deltaCol >= 0 && newCol + deltaCol < cols && 
56                       maze[newRow + deltaRow][newCol + deltaCol] == 0 && 
57                       (newRow != holeRow || newCol != holeCol)) {
58                    newRow += deltaRow;
59                    newCol += deltaCol;
60                    steps++;
61                }
62              
63                // Update if we found a shorter path or lexicographically smaller path with same distance
64                if (distance[newRow][newCol] > steps || 
65                    (distance[newRow][newCol] == steps && 
66                     paths[currentRow][currentCol] + directionChar < paths[newRow][newCol])) {
67                  
68                    distance[newRow][newCol] = steps;
69                    paths[newRow][newCol] = paths[currentRow][currentCol] + directionChar;
70                  
71                    // Only add to queue if we haven't reached the hole yet
72                    if (newRow != holeRow || newCol != holeCol) {
73                        bfsQueue.push({newRow, newCol});
74                    }
75                }
76            }
77        }
78      
79        // Return the path to hole, or "impossible" if no path exists
80        return paths[holeRow][holeCol].empty() ? "impossible" : paths[holeRow][holeCol];
81    }
82};
83
1function findShortestWay(maze: number[][], ball: number[], hole: number[]): string {
2    // Get maze dimensions
3    const rows = maze.length;
4    const cols = maze[0].length;
5  
6    // Starting position (ball) and target position (hole)
7    const startRow = ball[0];
8    const startCol = ball[1];
9    const holeRow = hole[0];
10    const holeCol = hole[1];
11  
12    // BFS queue to explore positions as [row, col] pairs
13    const bfsQueue: [number, number][] = [];
14    bfsQueue.push([startRow, startCol]);
15  
16    // Distance matrix to track minimum steps to reach each position
17    const distance: number[][] = Array(rows).fill(null).map(() => Array(cols).fill(Number.MAX_SAFE_INTEGER));
18    distance[startRow][startCol] = 0;
19  
20    // Path matrix to track the direction sequence to reach each position
21    const paths: string[][] = Array(rows).fill(null).map(() => Array(cols).fill(""));
22  
23    // Direction vectors with corresponding direction characters
24    // Format: [deltaRow, deltaCol, directionChar]
25    const directions: [number, number, string][] = [
26        [-1, 0, 'u'],  // up
27        [1, 0, 'd'],   // down
28        [0, -1, 'l'],  // left
29        [0, 1, 'r']    // right
30    ];
31  
32    // BFS to find shortest path
33    while (bfsQueue.length > 0) {
34        // Dequeue current position
35        const currentPos = bfsQueue.shift()!;
36        const currentRow = currentPos[0];
37        const currentCol = currentPos[1];
38      
39        // Try rolling the ball in each direction
40        for (const direction of directions) {
41            const deltaRow = direction[0];
42            const deltaCol = direction[1];
43            const directionChar = direction[2];
44          
45            // Roll the ball until it hits a wall or falls into the hole
46            let newRow = currentRow;
47            let newCol = currentCol;
48            let steps = distance[currentRow][currentCol];
49          
50            // Keep rolling while:
51            // 1. Next position is within bounds
52            // 2. Next position is not a wall (maze value is 0)
53            // 3. Current position is not the hole
54            while (newRow + deltaRow >= 0 && newRow + deltaRow < rows && 
55                   newCol + deltaCol >= 0 && newCol + deltaCol < cols && 
56                   maze[newRow + deltaRow][newCol + deltaCol] === 0 && 
57                   (newRow !== holeRow || newCol !== holeCol)) {
58                newRow += deltaRow;
59                newCol += deltaCol;
60                steps++;
61            }
62          
63            // Update if we found a shorter path or lexicographically smaller path with same distance
64            if (distance[newRow][newCol] > steps || 
65                (distance[newRow][newCol] === steps && 
66                 paths[currentRow][currentCol] + directionChar < paths[newRow][newCol])) {
67              
68                // Update distance and path for this position
69                distance[newRow][newCol] = steps;
70                paths[newRow][newCol] = paths[currentRow][currentCol] + directionChar;
71              
72                // Only add to queue if we haven't reached the hole yet
73                // (hole is the final destination, no need to explore from there)
74                if (newRow !== holeRow || newCol !== holeCol) {
75                    bfsQueue.push([newRow, newCol]);
76                }
77            }
78        }
79    }
80  
81    // Return the path to hole, or "impossible" if no path exists
82    return paths[holeRow][holeCol] === "" ? "impossible" : paths[holeRow][holeCol];
83}
84

Time and Space Complexity

Time Complexity: O(m * n * max(m, n))

The algorithm uses BFS with a deque. In the worst case, each cell (i, j) in the maze can be visited multiple times (when we find shorter paths or lexicographically smaller paths). For each cell visited, we explore 4 directions. In each direction, the ball rolls until it hits a wall or the hole, which takes at most max(m, n) steps in the worst case. Since we might process each of the m * n cells, and for each cell we might roll the ball up to max(m, n) distance in 4 directions, the time complexity is O(m * n * max(m, n)).

Space Complexity: O(m * n)

The space complexity consists of:

  • The dist matrix: O(m * n) to store the minimum distance to each cell
  • The path matrix: O(m * n) to store the path string to each cell (though each string can vary in length, in the worst case the path length is bounded by O(m * n))
  • The deque q: In the worst case, it can contain all cells, which is O(m * n)

Therefore, the overall space complexity is O(m * n).

Common Pitfalls

1. Not Handling Revisited Positions Correctly

Pitfall: A common mistake is using a simple visited set that permanently marks positions as visited after the first encounter. This prevents finding better paths that might arrive at the same position later.

Why it's wrong: In this problem, we might reach the same position multiple times with:

  • Different distances
  • Same distance but different paths (where one is lexicographically smaller)

Example scenario:

maze = [[0,0,0],
        [1,0,0],
        [0,0,0]]
ball = [0,0]
hole = [2,2]

Path 1: right→right→down→down = "rrdd" (distance: 4)
Path 2: down→down→right→right = "ddrr" (distance: 4)

Both paths have the same distance, but "ddrr" is lexicographically smaller.

Solution: Instead of a visited set, maintain:

  • A distances matrix to track minimum distance to each position
  • A paths matrix to track the path string to each position
  • Update a position when finding a shorter path OR an equal-length but lexicographically smaller path

2. Incorrect Rolling Simulation

Pitfall: Stopping the ball one position before the wall instead of at the last valid position:

# WRONG - stops too early
while 0 <= next_row + row_delta < rows and maze[next_row + row_delta][next_col + col_delta] == 0:
    next_row += row_delta
    next_col += col_delta

Why it's wrong: This doesn't move the ball to the last empty space before the wall.

Solution: Check if the NEXT position is valid before moving:

# CORRECT - checks next position before moving
while (0 <= next_row + row_delta < rows 
       and 0 <= next_col + col_delta < cols 
       and maze[next_row + row_delta][next_col + col_delta] == 0):
    next_row += row_delta
    next_col += col_delta
    steps += 1

3. Not Stopping at the Hole During Rolling

Pitfall: Allowing the ball to roll past the hole if there's empty space beyond it:

# WRONG - doesn't check for hole during rolling
while (0 <= next_row + row_delta < rows 
       and 0 <= next_col + col_delta < cols 
       and maze[next_row + row_delta][next_col + col_delta] == 0):
    next_row += row_delta
    next_col += col_delta

Why it's wrong: The ball should immediately drop into the hole when rolling over it, not continue past it.

Solution: Add a check to stop if current position is the hole:

# CORRECT - stops at hole
while (0 <= next_row + row_delta < rows 
       and 0 <= next_col + col_delta < cols 
       and maze[next_row + row_delta][next_col + col_delta] == 0
       and (next_row != hole_row or next_col != hole_col)):  # Stop if at hole
    next_row += row_delta
    next_col += col_delta

4. Adding the Hole Position to Queue

Pitfall: Adding the hole position to the BFS queue for further exploration:

# WRONG - allows rolling from the hole
if distances[next_row][next_col] > steps:
    distances[next_row][next_col] = steps
    queue.append((next_row, next_col))  # This might add the hole!

Why it's wrong: Once the ball falls into the hole, it stops. We shouldn't explore paths starting from the hole.

Solution: Check if the position is the hole before adding to queue:

# CORRECT - doesn't add hole to queue
if distances[next_row][next_col] > steps:
    distances[next_row][next_col] = steps
    if next_row != hole_row or next_col != hole_col:
        queue.append((next_row, next_col))

5. Incorrect Distance Counting

Pitfall: Including the starting position in the distance count or excluding the hole position:

# WRONG - starts counting from 1
steps = 1  # Should start from distances[current_row][current_col]

Why it's wrong: The problem specifies distance should exclude the start position but include the hole position.

Solution: Initialize steps from the current position's distance and increment for each space traveled:

# CORRECT
steps = distances[current_row][current_col]
while ...:
    next_row += row_delta
    next_col += col_delta
    steps += 1  # Count each space traveled
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

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

Load More