Backtracking · Medium
149. Rat in a Maze - Count Distinct Paths
Topics: Backtracking, Matrix
Solve it on DeVert Campus - free code runner
Problem
A rat starts at the top-left cell of an n x n maze and must reach the bottom-right cell, moving only right or down, and only through cells marked 1 (cells marked 0 are blocked). Count the number of distinct such paths.
Input and output
Input: The first line contains an integer n. The next n lines each contain n space-separated integers (0 or 1) representing the maze.
Output: Print a single integer - the number of distinct paths from the top-left to the bottom-right cell moving only right or down through open cells.
Example
Input: 4 1 0 0 0 1 1 0 1 0 1 0 0 1 1 1 1 Output: 1
Constraints
1 <= n <= 100
Key observation
A blocked START or END cell (if input allowed such a case) would immediately make the answer 0 - a quick sanity check worth keeping in mind even though this specific problem's example doesn't test it directly.
Intuition
Count how many distinct paths exist from a maze's top-left to bottom-right, moving only right or down through open cells.
Brute force: Use pure backtracking, recursively trying right and down moves and counting how many recursive calls reach the destination - this works correctly but can recompute the SAME sub-path counts repeatedly when multiple routes pass through the same cell, especially on larger grids (n up to 100 makes this recomputation costly without memoization).
Optimised: Converting the backtracking recursion into a bottom-up DP table means each cell's path-count is computed exactly once, reused directly by every cell that could reach it - turning potentially exponential re-exploration into a clean O(n²) table fill.
Top-down memoized recursion
Use the exact same recursive relation as the brute approach, but store the result for each (row, col) pair in a memo table the first time it's computed, and simply return the cached value on any later request for that same cell. Since every one of the n^2 cells now has its path count computed only once, the exponential blowup disappears and the total work becomes proportional to the number of cells in the maze.
Time: O(n^2)
Space: O(n^2)
Bottom-up DP with a rolling row
Fill an n x n table iteratively from the top-left down: dp[row][col] is 0 if the cell is blocked, otherwise it's the sum of dp[row-1][col] (arriving from above) and dp[row][col-1] (arriving from the left), with dp[0][0] set to 1 if that cell is open; the answer is dp[n-1][n-1]. Since each row only ever depends on the row directly above it, the table can be computed while keeping just a single rolling row in memory instead of the full n x n grid, cutting the space usage down substantially while keeping the same linear-per-cell work.
Time: O(n^2)
Space: O(n) (single rolling row)
Plain recursive backtracking
Define recurse(row, col) as the number of distinct paths from that cell to the bottom-right, using the relation recurse(row, col) = recurse(row+1, col) + recurse(row, col+1) whenever the current cell is open (1), with 0 returned immediately for blocked cells or out-of-bounds positions, and 1 at the destination. Because different root-to-cell paths reach the same (row, col) repeatedly, this recomputes the same subproblem's path count many times over, causing the total work to grow combinatorially with the maze size.
Time: Exponential (up to O(2^n) roughly)
Space: O(n) recursion depth
Step by step
1. Build a DP table where dp[i][j] is the number of ways to reach cell (i,j) moving only right or down through open cells.
2. If the cell itself is blocked, dp[i][j] is immediately 0.
3. Otherwise, dp[i][j] is the sum of the ways to reach it from above (dp[i-1][j]) and from the left (dp[i][j-1]).
Complexity
Time: O(n²) - filling the DP table, one cell at a time.
Space: O(n²) for the full table (reducible to O(n) with a rolling 1D array, since each row only depends on the row above it).
Edge cases
Test n = 1, a maze where the start or end cell is blocked (0 paths), and n = 100 for performance.
Interview tip
Be ready to explain the direct connection between this DP solution and the 'backtracking that would explore every path individually' - recognizing that DP here is really just 'memoized backtracking' reframed as a table-filling process.