Rat in a Maze Problem in DSA Typescript - Time & Space Complexity
We want to understand how the time needed to solve the Rat in a Maze problem changes as the maze size grows.
Specifically, how does the search for a path through the maze take longer when the maze gets bigger?
Analyze the time complexity of the following code snippet.
function solveMaze(maze: number[][], x: number, y: number, solution: number[][]): boolean {
const n = maze.length;
if (x === n - 1 && y === n - 1) {
solution[x][y] = 1;
return true;
}
if (x >= 0 && y >= 0 && x < n && y < n && maze[x][y] === 1) {
solution[x][y] = 1;
if (solveMaze(maze, x + 1, y, solution)) return true;
if (solveMaze(maze, x, y + 1, solution)) return true;
solution[x][y] = 0;
return false;
}
return false;
}
This code tries to find a path from the top-left to the bottom-right of a maze using backtracking.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls exploring each cell in the maze.
- How many times: Potentially, each cell is visited multiple times during backtracking.
As the maze size grows, the number of possible paths grows very fast because the rat can move in multiple directions at each step.
| Input Size (n) | Approx. Operations |
|---|---|
| 2 | Few recursive calls, easy to check all paths. |
| 5 | Many more paths to explore, operations increase quickly. |
| 10 | Huge number of possible paths, operations grow very fast. |
Pattern observation: The time grows very fast, much faster than just doubling or squaring; it grows exponentially with maze size.
Time Complexity: O(2^{n^2})
This means the time needed can grow extremely fast as the maze size increases, because the rat tries many possible paths.
[X] Wrong: "The rat only moves forward, so time grows linearly with maze size."
[OK] Correct: The rat can move in multiple directions and backtrack, so many paths are checked, making the time grow much faster than linear.
Understanding this problem helps you think about how exploring many options affects time, a skill useful for many search and path problems.
"What if we added a rule that the rat can only move right or down? How would the time complexity change?"
Practice
Rat in a Maze Problem in data structures and algorithms?Solution
Step 1: Understand the problem context
The Rat in a Maze problem involves navigating through a maze represented as a grid to find a path from the start cell to the destination cell.Step 2: Identify the goal
The goal is to find a valid path that the rat can follow to reach the destination without crossing walls or blocked cells.Final Answer:
Find a path from the start to the destination in a maze -> Option DQuick Check:
Goal = Find path [OK]
- Confusing path finding with counting walls
- Thinking the problem is about sorting cells
- Assuming shortest path is always required
Solution
Step 1: Understand array initialization in TypeScript
UsingArray.fromwith a mapping function creates independent inner arrays, avoiding reference issues.Step 2: Analyze each option
const maze: number[][] = Array(4).fill(Array(4).fill(0)); creates inner arrays by reference, causing all rows to point to the same array. const maze: number[][] = Array.from({length: 4}, () => Array(4).fill(0)); correctly creates separate arrays for each row. Options B and C use invalid syntax for 2D arrays.Final Answer:
const maze: number[][] = Array.from({length: 4}, () => Array(4).fill(0)); -> Option AQuick Check:
Correct 2D array init = const maze: number[][] = Array.from({length: 4}, () => Array(4).fill(0)); [OK]
- Using fill with nested arrays causing shared references
- Incorrect syntax for 2D array creation
- Confusing array size parameters
const maze = [
[1, 0, 0, 0],
[1, 1, 0, 1],
[0, 1, 0, 0],
[1, 1, 1, 1]
];
function isSafe(x: number, y: number): boolean {
return x >= 0 && y >= 0 && x < 4 && y < 4 && maze[x][y] === 1;
}
function solveMaze(x: number, y: number, path: string[]): boolean {
if (x === 3 && y === 3) {
path.push(`(${x},${y})`);
return true;
}
if (isSafe(x, y)) {
path.push(`(${x},${y})`);
if (solveMaze(x + 1, y, path)) return true;
if (solveMaze(x, y + 1, path)) return true;
path.pop();
}
return false;
}
const path: string[] = [];
if (solveMaze(0, 0, path)) {
console.log(path.join(' -> '));
} else {
console.log('No path found');
}Solution
Step 1: Trace the recursive path from (0,0)
Starting at (0,0), the rat moves down to (1,0) since maze[1][0] = 1. Then right to (1,1), down to (2,1), down to (3,1), right to (3,2), and right to (3,3).Step 2: Verify path validity and output
All these cells are safe (value 1). The path is recorded and printed as shown in (0,0) -> (1,0) -> (1,1) -> (2,1) -> (3,1) -> (3,2) -> (3,3).Final Answer:
(0,0) -> (1,0) -> (1,1) -> (2,1) -> (3,1) -> (3,2) -> (3,3) -> Option BQuick Check:
Path found = (0,0) -> (1,0) -> (1,1) -> (2,1) -> (3,1) -> (3,2) -> (3,3) [OK]
- Assuming movement to blocked cells (0 values)
- Confusing row and column indices
- Ignoring backtracking when path fails
function solveMaze(x: number, y: number, path: string[]): boolean {
if (x === 3 && y === 3) {
path.push(`(${x},${y})`);
return true;
}
if (isSafe(x, y)) {
path.push(`(${x},${y})`);
if (solveMaze(x + 1, y, path)) return true;
if (solveMaze(x, y + 1, path)) return true;
path.pop();
}
return false;
}Solution
Step 1: Analyze the recursion and path tracking
The function adds the current cell to path but does not remove it if both recursive calls fail, causing incorrect path accumulation.Step 2: Identify missing backtracking
Backtracking requires removing the current cell from path when no path forward is found, which is missing here.Final Answer:
Missing backtracking step to remove current cell from path when dead end is reached -> Option CQuick Check:
Backtracking needed = Missing backtracking step to remove current cell from path when dead end is reached [OK]
- Forgetting to remove cell from path on failure
- Incorrect base case coordinates
- Ignoring isSafe checks before path push
Solution
Step 1: Understand the requirement to find all paths
Finding all paths requires exploring every possible route without stopping at the first success.Step 2: Choose backtracking to explore all safe moves
Backtracking allows exploring all safe moves recursively, storing each complete path separately before backtracking to try other routes.Final Answer:
Use backtracking to explore all safe moves, storing each complete path separately -> Option AQuick Check:
All paths = Backtracking exploration [OK]
- Stopping after first path found
- Using greedy moves that miss paths
- Using shortest path algorithms instead of all paths
Ready to prove it?
Pass the test and this pattern moves unknown
