Bird
Raised Fist0
DSA Rustprogramming

Rat in a Maze Problem in DSA Rust

Choose your learning style10 modes available
Mental Model
Find a path from start to end in a grid by moving only through allowed cells.
Analogy: Imagine a rat trying to find cheese in a maze by walking only on open paths and avoiding walls.
S -> 0 1 0
0 -> 0 0 0
1 -> 0 1 E

S = Start, E = End, 0 = open path, 1 = wall
Dry Run Walkthrough
Input: maze: [[1,0,1,0],[1,0,0,0],[0,1,0,1],[0,0,0,1]], start: (0,1), end: (3,2)
Goal: Find a path from start (0,1) to end (3,2) moving only on 0s
Step 1: Start at (0,1), mark as part of path
[X] -> 0 1 0
1 -> 0 0 0
0 -> 1 0 1
0 -> 0 0 1
Why: We begin exploring from the start cell
Step 2: Move down to (1,1), mark as part of path
1 -> [X] 0 0
1 -> 0 0 0
0 -> 1 0 1
0 -> 0 0 1
Why: Down is open and closer to the goal
Step 3: Move right to (1,2), mark as part of path
1 -> 0 [X] 0
1 -> 0 0 0
0 -> 1 0 1
0 -> 0 0 1
Why: Right is open and leads towards the goal
Step 4: Move right to (1,3), mark as part of path
1 -> 0 0 [X]
1 -> 0 0 0
0 -> 1 0 1
0 -> 0 0 1
Why: Continue moving right on open path
Step 5: Move down to (2,3), blocked by wall, backtrack
1 -> 0 0 [X]
1 -> 0 0 0
0 -> 1 0 1
0 -> 0 0 1
Why: Cannot move into wall, must try other directions
Step 6: Backtrack to (1,2), try down to (2,2), mark as part of path
1 -> 0 0 0
1 -> 0 0 [X]
0 -> 1 [X] 1
0 -> 0 0 1
Why: Down is open, try alternative path
Step 7: Move down to (3,2), mark as part of path (goal reached)
1 -> 0 0 0
1 -> 0 0 0
0 -> 1 0 1
0 -> 0 [X] 1
Why: Reached the goal cell
Result:
Path found: (0,1) -> (1,1) -> (1,2) -> (1,3) -> (2,2) -> (3,2)
Annotated Code
DSA Rust
fn is_safe(maze: &Vec<Vec<i32>>, x: usize, y: usize) -> bool {
    x < maze.len() && y < maze[0].len() && maze[x][y] == 0
}

fn solve_maze_util(maze: &Vec<Vec<i32>>, x: usize, y: usize, solution: &mut Vec<Vec<i32>>) -> bool {
    if x == maze.len() - 1 && y == maze[0].len() - 1 {
        solution[x][y] = 1;
        return true;
    }

    if is_safe(maze, x, y) && solution[x][y] == 0 {
        solution[x][y] = 1;

        if x + 1 < maze.len() && solve_maze_util(maze, x + 1, y, solution) {
            return true;
        }

        if y + 1 < maze[0].len() && solve_maze_util(maze, x, y + 1, solution) {
            return true;
        }

        solution[x][y] = 0; // backtrack
        return false;
    }

    false
}

fn solve_maze(maze: Vec<Vec<i32>>) {
    let n = maze.len();
    let m = maze[0].len();
    let mut solution = vec![vec![0; m]; n];

    if solve_maze_util(&maze, 0, 0, &mut solution) {
        for row in solution {
            println!("{:?}", row);
        }
    } else {
        println!("No path found");
    }
}

fn main() {
    let maze = vec![
        vec![0, 0, 1, 0],
        vec![1, 0, 0, 0],
        vec![0, 1, 0, 1],
        vec![0, 0, 0, 0],
    ];
    solve_maze(maze);
}
if x == maze.len() - 1 && y == maze[0].len() - 1 {
check if current cell is goal
if is_safe(maze, x, y) && solution[x][y] == 0 {
check if current cell is safe and not visited
solution[x][y] = 1;
mark current cell as part of path
if x + 1 < maze.len() && solve_maze_util(maze, x + 1, y, solution) {
try moving down recursively
if y + 1 < maze[0].len() && solve_maze_util(maze, x, y + 1, solution) {
try moving right recursively
solution[x][y] = 0; // backtrack
unmark cell if path does not lead to goal
OutputSuccess
[1, 1, 0, 0] [0, 1, 1, 1] [0, 0, 1, 0] [0, 0, 1, 1]
Complexity Analysis
Time: O(2^(n*m)) because in worst case we explore all paths in the grid
Space: O(n*m) for the recursion stack and solution matrix
vs Alternative: Compared to BFS which uses a queue and finds shortest path, this DFS approach explores all paths and may be slower
Edge Cases
Empty maze
No path found immediately
DSA Rust
if x == maze.len() - 1 && y == maze[0].len() - 1 {
Start or end blocked
No path found because start or end cell is not safe
DSA Rust
if is_safe(maze, x, y) && solution[x][y] == 0 {
Maze with no path
Backtracking exhausts all options and prints no path found
DSA Rust
solution[x][y] = 0; // backtrack
When to Use This Pattern
When you see a grid with blocked and open cells and need to find a path from start to end, reach for backtracking DFS because it tries all possible paths systematically.
Common Mistakes
Mistake: Not marking visited cells leading to infinite recursion
Fix: Mark cells as part of path before recursive calls and unmark on backtrack
Mistake: Trying to move outside maze boundaries
Fix: Check boundaries before recursive calls
Summary
Finds a path through a maze from start to end using backtracking.
Use when you need to explore all possible paths in a grid with obstacles.
The key is to mark your path and backtrack when stuck to try other routes.

Practice

(1/5)
1. What is the main goal of the Rat in a Maze problem in data structures?
easy
A. Find a path from the start to the destination in a maze
B. Count the total number of cells in the maze
C. Calculate the shortest distance between two points in a graph
D. Sort the maze cells in ascending order

Solution

  1. Step 1: Understand the problem goal

    The Rat in a Maze problem asks to find a path from the start cell (usually top-left) to the destination cell (usually bottom-right) in a maze represented by a grid.
  2. Step 2: Identify the correct goal

    The goal is not counting cells, sorting, or shortest distance but finding a valid path through allowed cells.
  3. Final Answer:

    Find a path from the start to the destination in a maze -> Option A
  4. Quick Check:

    Goal = Find path [OK]
Hint: Focus on pathfinding, not counting or sorting [OK]
Common Mistakes:
  • Confusing pathfinding with counting cells
  • Thinking it finds shortest path always
  • Mixing it with sorting or graph distance problems
2. Which of the following Rust function signatures is correct for a recursive function solving the Rat in a Maze problem?
easy
A. fn solve_maze(maze: Vec<i32>, x: usize, y: usize) -> Vec<(usize, usize)>
B. fn solve_maze(maze: Vec, x: i32, y: i32) -> i32
C. fn solve_maze(maze: &mut Vec<i32>, x: usize, y: usize) -> bool
D. fn solve_maze(maze: &Vec, x: usize, y: usize, path: &mut Vec<(usize, usize)>) -> bool

Solution

  1. Step 1: Check parameter types for maze and coordinates

    The maze is a 2D grid, so it should be a reference to a vector of vectors of integers (&Vec). Coordinates are usize for indexing.
  2. Step 2: Check return type and path parameter

    The function returns bool to indicate success and uses a mutable path vector to store the route.
  3. Final Answer:

    fn solve_maze(maze: &Vec, x: usize, y: usize, path: &mut Vec<(usize, usize)>) -> bool -> Option D
  4. Quick Check:

    Correct signature uses references and bool return [OK]
Hint: Use references for maze and bool return for success [OK]
Common Mistakes:
  • Passing maze by value causing unnecessary copying
  • Using wrong coordinate types (i32 instead of usize)
  • Returning wrong types like i32 or Vec instead of bool
3. Given the following Rust code snippet for Rat in a Maze, what will be printed?
fn main() {
    let maze = vec![
        vec![1, 0, 0, 0],
        vec![1, 1, 0, 1],
        vec![0, 1, 0, 0],
        vec![1, 1, 1, 1],
    ];
    let mut path = Vec::new();
    if solve_maze(&maze, 0, 0, &mut path) {
        println!("Path found: {:?}", path);
    } else {
        println!("No path found");
    }
}

fn solve_maze(maze: &Vec, x: usize, y: usize, path: &mut Vec<(usize, usize)>) -> bool {
    let n = maze.len();
    if x == n - 1 && y == n - 1 {
        path.push((x, y));
        return true;
    }
    if x < n && y < n && maze[x][y] == 1 {
        path.push((x, y));
        if x + 1 < n && solve_maze(maze, x + 1, y, path) {
            return true;
        }
        if y + 1 < n && solve_maze(maze, x, y + 1, path) {
            return true;
        }
        path.pop();
    }
    false
}
medium
A. Path found: [(0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3)]
B. Path found: [(0, 0), (0, 1), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3)]
C. No path found
D. Path found: [(0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (3, 2), (3, 3)]

Solution

  1. Step 1: Trace the recursive calls from (0,0)

    Start at (0,0) which is 1 (allowed). Try moving down to (1,0) which is 1, then (2,0) is 0 (blocked), so backtrack. Then try right from (1,0) to (1,1) which is 1.
  2. Step 2: Continue path to destination

    From (1,1), down to (2,1) is 1, then down to (3,1) is 1, right to (3,2) is 1, and right to (3,3) is 1 (destination). Path is [(0,0),(1,0),(1,1),(2,1),(3,1),(3,2),(3,3)].
  3. Final Answer:

    Path found: [(0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3)] -> Option A
  4. Quick Check:

    Recursive path = Path found: [(0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3)] [OK]
Hint: Follow down then right moves recursively [OK]
Common Mistakes:
  • Assuming path goes right first instead of down
  • Not backtracking correctly on blocked cells
  • Confusing coordinates order in path
4. Identify the bug in this Rust code snippet for Rat in a Maze and select the fix:
fn solve_maze(maze: &Vec, x: usize, y: usize, path: &mut Vec<(usize, usize)>) -> bool {
    let n = maze.len();
    if x == n - 1 && y == n - 1 {
        path.push((x, y));
        return true;
    }
    if x < n && y < n && maze[x][y] == 1 {
        path.push((x, y));
        if solve_maze(maze, x + 1, y, path) {
            return true;
        }
        if solve_maze(maze, x, y + 1, path) {
            return true;
        }
        path.pop();
    }
    false
}
medium
A. Change maze parameter to mutable reference
B. Remove path.pop() to keep all visited cells
C. Add boundary checks before recursive calls to avoid out-of-bounds
D. Return i32 instead of bool for success

Solution

  1. Step 1: Analyze recursive calls for boundary safety

    The recursive calls use x+1 and y+1 without checking if they exceed maze size, risking out-of-bounds panic.
  2. Step 2: Fix by adding boundary checks before recursion

    Adding checks like x + 1 < n and y + 1 < n before calling solve_maze prevents invalid indexing.
  3. Final Answer:

    Add boundary checks before recursive calls to avoid out-of-bounds -> Option C
  4. Quick Check:

    Boundary checks prevent panic [OK]
Hint: Always check indices before recursive calls [OK]
Common Mistakes:
  • Ignoring index bounds causing runtime panic
  • Changing maze to mutable unnecessarily
  • Removing path.pop() causing wrong paths
5. You want to modify the Rat in a Maze solution in Rust to find all possible paths from start to finish instead of just one. Which approach is best?
hard
A. Use a queue to perform breadth-first search and return the shortest path only
B. Return a vector of paths and explore all possible moves recursively without stopping at first success
C. Stop recursion as soon as one path is found to save time
D. Modify the maze to mark visited cells permanently to avoid revisiting

Solution

  1. Step 1: Understand requirement to find all paths

    Finding all paths means exploring every possible route without stopping at the first success.
  2. Step 2: Use recursion to explore all moves and collect paths

    Return a vector of paths and do not return early. Backtrack properly to explore all options.
  3. Final Answer:

    Return a vector of paths and explore all possible moves recursively without stopping at first success -> Option B
  4. Quick Check:

    Explore all paths recursively [OK]
Hint: Collect all paths, don't stop at first success [OK]
Common Mistakes:
  • Stopping recursion early losing other paths
  • Using BFS only for shortest path, not all paths
  • Marking visited permanently blocking other paths
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard