Close Menu
    Code and Debug
    • Home
    • Our Courses
    • Blog
    • About Us
    • Contact Us
    Facebook X (Twitter) Instagram YouTube WhatsApp
    • Home
    • Our Courses
    • Blog
    • About Us
    • Contact Us
    Facebook Instagram YouTube LinkedIn WhatsApp
    Code and Debug – BlogCode and Debug – Blog
    Code and Debug – BlogCode and Debug – Blog
    Home»Data Structures & Algorithms»Rat in a Maze Problem – I | GFG Practice | 2 different solutions
    Data Structures & Algorithms

    Rat in a Maze Problem – I | GFG Practice | 2 different solutions

    codeanddebugBy codeanddebug22 July 2025No Comments15 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Telegram Email
    Featured image of a question of rat in a maze
    Share
    Facebook Twitter LinkedIn Pinterest Email

    Consider a rat placed at position (0, 0) in an n x n square matrix mat[][]. The rat’s goal is to reach the destination at position (n-1, n-1). The rat can move in four possible directions: ‘U'(up), ‘D'(down), ‘L’ (left), ‘R’ (right).

    The matrix contains only two possible values:

    • 0: A blocked cell through which the rat cannot travel.
    • 1: A free cell that the rat can pass through.

    Your task is to find all possible paths the rat can take to reach the destination, starting from (0, 0) and ending at (n-1, n-1), under the condition that the rat cannot revisit any cell along the same path. Furthermore, the rat can only move to adjacent cells that are within the bounds of the matrix and not blocked.
    If no path exists, return an empty list.

    Note: Return the final result vector in lexicographically smallest order.

    Here’s the [Problem Link] to begin with.

    Examples:

    Input: mat[][] = [[1, 0, 0, 0], [1, 1, 0, 1], [1, 1, 0, 0], [0, 1, 1, 1]]
    Output: ["DDRDRR", "DRDDRR"]
    Explanation: The rat can reach the destination at (3, 3) from (0, 0) by two paths - DRDDRR and DDRDRR, when printed in sorted order we get DDRDRR DRDDRR.
    Input: mat[][] = [[1, 0], [1, 0]]
    Output: []
    Explanation: No path exists as the destination cell is blocked.
    Input: mat = [[1, 1, 1], [1, 0, 1], [1, 1, 1]]
    Output: ["DDRR", "RRDD"]
    Explanation: The rat has two possible paths to reach the destination: 1. "DDRR" 2. "RRDD", These are returned in lexicographically sorted order.

    Constraints:
    2 ≤ mat.size() ≤ 5
    0 ≤ mat[i][j] ≤ 1

    Contents:
     [show]
    • Solution 1: Brute Force Approach (Explicit Direction Handling)
      • Intuition
      • Detailed Approach
      • Code
      • Code Explanation
      • Dry Run
      • Time and Space Complexity
      • Simplifying It
    • Solution 2: Optimal Approach (Direction Arrays for Clean Code)
      • Intuition
      • Detailed Approach
      • Code
      • Code Explanation
      • Dry Run
      • Time and Space Complexity
      • Simplifying It
    • Summary

    Solution 1: Brute Force Approach (Explicit Direction Handling)

    Intuition

    Think of this like helping a rat navigate through a maze by trying every possible route! The brute force approach explicitly handles each of the four possible directions (Down, Left, Right, Up) with separate if-conditions. For each direction, we check if it’s valid (within bounds, not visited, and not blocked), then recursively explore that path. It’s like being a maze solver who methodically checks “Can I go down? Can I go left? Can I go right? Can I go up?” at every junction, trying each valid option one by one.

    Detailed Approach

    1. Explicit Direction Checks: Use separate if-statements for each direction (D, L, R, U).
    2. Boundary & Validity Checks: For each direction, check:
      • Within maze boundaries
      • Cell not already visited (to avoid cycles)
      • Cell is open (value = 1)
    3. Backtracking Pattern:
      • Mark current cell as visited
      • Recursively explore the direction
      • Unmark cell (backtrack) when returning
    4. Path Building: Build path string by appending direction characters (“D”, “L”, “R”, “U”).
    5. Base Case: When rat reaches (N-1, N-1), add the complete path to results.

    Code

    def findPathHelper(
        i: int, j: int, a: List[List[int]], n: int, 
        ans: List[str], move: str, vis: List[List[int]]
    ):
        # Base case: reached destination
        if i == n - 1 and j == n - 1:
            ans.append(move)
            return
    
        # Try going downward (i+1, j)
        if i + 1 < n and not vis[i + 1][j] and a[i + 1][j] == 1:
            vis[i][j] = 1  # Mark current cell as visited
            findPathHelper(i + 1, j, a, n, ans, move + "D", vis)
            vis[i][j] = 0  # Backtrack: unmark current cell
    
        # Try going left (i, j-1)
        if j - 1 >= 0 and not vis[i][j - 1] and a[i][j - 1] == 1:
            vis[i][j] = 1
            findPathHelper(i, j - 1, a, n, ans, move + "L", vis)
            vis[i][j] = 0
    
        # Try going right (i, j+1)
        if j + 1 < n and not vis[i][j + 1] and a[i][j + 1] == 1:
            vis[i][j] = 1
            findPathHelper(i, j + 1, a, n, ans, move + "R", vis)
            vis[i][j] = 0
    
        # Try going upward (i-1, j)
        if i - 1 >= 0 and not vis[i - 1][j] and a[i - 1][j] == 1:
            vis[i][j] = 1
            findPathHelper(i - 1, j, a, n, ans, move + "U", vis)
            vis[i][j] = 0
    
    def ratMaze(matrix: List[List[int]]) -> List[str]:
        n = len(matrix)
        ans = []
        vis = [[0 for _ in range(n)] for _ in range(n)]  # Visited array
        
        # Only start if source cell is open
        if matrix[0][0] == 1:
            findPathHelper(0, 0, matrix, n, ans, "", vis)
        return ans

    Code Explanation

    This brute force solution explicitly handles each direction with separate if-conditions. Each direction check follows the same pattern: validate boundaries, check if cell is unvisited and open, then mark current cell as visited, recursively explore, and backtrack by unmarking. The move string accumulates the path taken so far, and when we reach the destination, we add it to our results. The visited array prevents infinite loops by ensuring we don’t revisit cells in the current path.

    Dry Run

    Let’s trace through: matrix = [[1, 0, 0, 0], [1, 1, 0, 1], [1, 1, 0, 0], [0, 1, 1, 1]]

    graph TD
        Root["findPathHelper(0,0, move='', vis=all 0)<br/>Matrix: [[1,0,0,0],[1,1,0,1],[1,1,0,0],[0,1,1,1]]<br/>Start at (0,0), target (3,3)"]
        
        %% Level 0: From (0,0), check 4 directions
        Root --- A["Try Down to (1,0)<br/>Check: i+1=1 < 4 ✓, vis[1][0]=0 ✓, mat[1][0]=1 ✓<br/>Mark vis[0][0]=1, move='D'<br/>Recurse to (1,0)"]
        Root --- B["Try Left: j-1=-1 < 0 ❌<br/>Out of bounds"]
        Root --- C["Try Right to (0,1)<br/>Check: j+1=1 < 4 ✓, vis[0][1]=0 ✓, mat[0][1]=0 ❌<br/>Blocked cell"]
        Root --- D["Try Up: i-1=-1 < 0 ❌<br/>Out of bounds"]
        
        %% Level 1: From (1,0), check 4 directions  
        A --- A1["Try Down to (2,0)<br/>Check: mat[2][0]=1 ✓, not visited ✓<br/>Mark vis[1][0]=1, move='DD'<br/>Recurse to (2,0)"]
        A --- A2["Try Left: j-1=-1 < 0 ❌<br/>Out of bounds"]
        A --- A3["Try Right to (1,1)<br/>Check: mat[1][1]=1 ✓, not visited ✓<br/>Mark vis[1][0]=1, move='DR'<br/>Recurse to (1,1)"]
        A --- A4["Try Up to (0,0)<br/>Check: mat[0][0]=1 ✓, but vis[0][0]=1 ❌<br/>Already visited"]
        
        %% Level 2: From (2,0), check 4 directions
        A1 --- A1a["Try Down: mat[3][0]=0 ❌<br/>Blocked cell"]
        A1 --- A1b["Try Left: j-1=-1 < 0 ❌<br/>Out of bounds"]
        A1 --- A1c["Try Right to (2,1)<br/>Check: mat[2][1]=1 ✓, not visited ✓<br/>Mark vis[2][0]=1, move='DDR'<br/>Recurse to (2,1)"]
        A1 --- A1d["Try Up to (1,0)<br/>vis[1][0]=1 ❌<br/>Already visited"]
        
        %% Level 2: From (1,1), check 4 directions  
        A3 --- A3a["Try Down to (2,1)<br/>Check: mat[2][1]=1 ✓, not visited ✓<br/>Mark vis[1][1]=1, move='DRD'<br/>Recurse to (2,1)"]
        A3 --- A3b["Try Left to (1,0)<br/>vis[1][0]=1 ❌<br/>Already visited"]
        A3 --- A3c["Try Right to (1,2)<br/>mat[1][2]=0 ❌<br/>Blocked cell"]
        A3 --- A3d["Try Up to (0,1)<br/>mat[0][1]=0 ❌<br/>Blocked cell"]
        
        %% Level 3: From (2,1) via path DD, check 4 directions
        A1c --- A1c1["Try Down to (3,1)<br/>Check: mat[3][1]=1 ✓, not visited ✓<br/>Mark vis[2][1]=1, move='DDRD'<br/>Recurse to (3,1)"]
        A1c --- A1c2["Try Left to (2,0)<br/>vis[2][0]=1 ❌<br/>Already visited"]
        A1c --- A1c3["Try Right to (2,2)<br/>mat[2][2]=0 ❌<br/>Blocked cell"]
        A1c --- A1c4["Try Up to (1,1)<br/>mat[1][1]=1 ✓, not visited ✓<br/>Mark vis[2][1]=1, move='DDRU'<br/>Recurse to (1,1)"]
        
        %% Level 3: From (2,1) via path DR, check 4 directions
        A3a --- A3a1["Try Down to (3,1)<br/>Check: mat[3][1]=1 ✓, not visited ✓<br/>Mark vis[2][1]=1, move='DRDD'<br/>Recurse to (3,1)"]
        A3a --- A3a2["Try Left to (2,0)<br/>mat[2][0]=1 ✓, not visited ✓<br/>Mark vis[2][1]=1, move='DRDL'<br/>Recurse to (2,0)"]
        A3a --- A3a3["Try Right to (2,2)<br/>mat[2][2]=0 ❌<br/>Blocked cell"]
        A3a --- A3a4["Try Up to (1,1)<br/>vis[1][1]=1 ❌<br/>Already visited"]
        
        %% Level 4: From (3,1) via path DDRD
        A1c1 --- A1c1a["Try Down: i+1=4 >= 4 ❌<br/>Out of bounds"]
        A1c1 --- A1c1b["Try Left to (3,0)<br/>mat[3][0]=0 ❌<br/>Blocked cell"]
        A1c1 --- A1c1c["Try Right to (3,2)<br/>Check: mat[3][2]=1 ✓, not visited ✓<br/>Mark vis[3][1]=1, move='DDRDR'<br/>Recurse to (3,2)"]
        A1c1 --- A1c1d["Try Up to (2,1)<br/>vis[2][1]=1 ❌<br/>Already visited"]
        
        %% Level 4: From (3,1) via path DRDD
        A3a1 --- A3a1a["Try Down: i+1=4 >= 4 ❌<br/>Out of bounds"]
        A3a1 --- A3a1b["Try Left to (3,0)<br/>mat[3][0]=0 ❌<br/>Blocked cell"]
        A3a1 --- A3a1c["Try Right to (3,2)<br/>Check: mat[3][2]=1 ✓, not visited ✓<br/>Mark vis[3][1]=1, move='DRDDR'<br/>Recurse to (3,2)"]
        A3a1 --- A3a1d["Try Up to (2,1)<br/>vis[2][1]=1 ❌<br/>Already visited"]
        
        %% Level 5: From (3,2) via path DDRDR
        A1c1c --- A1c1c1["Try Down: i+1=4 >= 4 ❌<br/>Out of bounds"]
        A1c1c --- A1c1c2["Try Left to (3,1)<br/>vis[3][1]=1 ❌<br/>Already visited"]
        A1c1c --- A1c1c3["Try Right to (3,3)<br/>Check: mat[3][3]=1 ✓, not visited ✓<br/>i=3, j=3 == n-1=3 ✓<br/>Found destination!<br/>move='DDRDDR'"]
        A1c1c --- A1c1c4["Try Up to (2,2)<br/>mat[2][2]=0 ❌<br/>Blocked cell"]
        
        %% Level 5: From (3,2) via path DRDDR  
        A3a1c --- A3a1c1["Try Down: i+1=4 >= 4 ❌<br/>Out of bounds"]
        A3a1c --- A3a1c2["Try Left to (3,1)<br/>vis[3][1]=1 ❌<br/>Already visited"]
        A3a1c --- A3a1c3["Try Right to (3,3)<br/>Check: mat[3][3]=1 ✓, not visited ✓<br/>i=3, j=3 == n-1=3 ✓<br/>Found destination!<br/>move='DRDDRR'"]
        A3a1c --- A3a1c4["Try Up to (2,2)<br/>mat[2][2]=0 ❌<br/>Blocked cell"]
        
        %% Success cases
        A1c1c3 --- Success1["✅ Add 'DDRDDR' to result<br/>Backtrack and unmark vis arrays"]
        A3a1c3 --- Success2["✅ Add 'DRDDRR' to result<br/>Backtrack and unmark vis arrays"]
        
        %% Final result
        Success1 --- Final["Final Result: ['DDRDDR', 'DRDDRR']"]
        Success2 --- Final
    
        %% Styling
        style Success1 fill:#90EE90
        style Success2 fill:#90EE90
        style Final fill:#90EE90
        
        style B fill:#FFB6C1
        style C fill:#FFB6C1
        style D fill:#FFB6C1
        style A2 fill:#FFB6C1
        style A4 fill:#FFB6C1
        style A1a fill:#FFB6C1
        style A1b fill:#FFB6C1
        style A1d fill:#FFB6C1
        style A3b fill:#FFB6C1
        style A3c fill:#FFB6C1
        style A3d fill:#FFB6C1
        
        style A1c1c3 fill:#87CEEB
        style A3a1c fill:#87CEEB
        style A1c1 fill:#87CEEB
        style A3a1 fill:#87CEEB
        
        style Root fill:#E6E6FA
    

    For detailed dry run [Click here]

    Time and Space Complexity

    • Time Complexity: O(4^(N×N)) – In worst case, we explore 4 directions at each of N×N cells
    • Space Complexity: O(N×N) – Visited array plus maximum recursion depth of N×N

    Simplifying It

    This approach is like having a very methodical rat that at every junction says “Let me try going down first, then left, then right, then up” and carefully explores each direction one by one. It’s straightforward but involves a lot of repetitive code for each direction.


    Solution 2: Optimal Approach (Direction Arrays for Clean Code)

    Intuition

    Instead of writing separate code for each direction, why not be smart and use arrays to represent all directions uniformly? This is like having a compass that points to all four directions – we can loop through the directions instead of hardcoding each one. The key insight is that all four directions follow the same pattern: check validity, mark visited, recurse, backtrack. By using direction arrays (di, dj) and a direction string “DLRU”, we can handle all directions in a single loop, making the code much cleaner and more maintainable.

    Detailed Approach

    1. Direction Arrays: Use di = [+1, 0, 0, -1] and dj = [0, -1, +1, 0] to represent direction offsets.
    2. Direction String: Use "DLRU" to map array indices to direction characters.
    3. Unified Loop: Single for-loop to try all 4 directions instead of 4 separate if-statements.
    4. Same Logic: Each iteration follows the same pattern: calculate next position, validate, recurse, backtrack.
    5. Cleaner Code: Eliminates code duplication while maintaining the same algorithmic approach.

    Code

    def solve(
        i: int, j: int, a: List[List[int]], n: int,
        ans: List[str], move: str, vis: List[List[int]],
        di: List[int], dj: List[int]
    ):
        # Base case: reached destination
        if i == n - 1 and j == n - 1:
            ans.append(move)
            return
        
        dir = "DLRU"  # Direction characters corresponding to di, dj arrays
        
        # Try all 4 directions in a loop
        for ind in range(4):
            nexti = i + di[ind]  # Calculate next row
            nextj = j + dj[ind]  # Calculate next column
            
            # Check if next position is valid
            if (
                nexti >= 0 and nextj >= 0 and          # Within upper bounds
                nexti < n and nextj < n and            # Within lower bounds  
                not vis[nexti][nextj] and              # Not visited
                a[nexti][nextj] == 1                   # Open cell
            ):
                vis[i][j] = 1  # Mark current cell as visited
                solve(nexti, nextj, a, n, ans, move + dir[ind], vis, di, dj)
                vis[i][j] = 0  # Backtrack: unmark current cell
    
    def ratMaze(matrix: List[List[int]]) -> List[str]:
        n = len(matrix)
        ans = []
        vis = [[0 for _ in range(n)] for _ in range(n)]
        
        # Direction arrays: Down, Left, Right, Up
        di = [+1, 0, 0, -1]  # Row offsets
        dj = [0, -1, +1, 0]  # Column offsets
        
        # Only start if source cell is open
        if matrix[0][0] == 1:
            solve(0, 0, matrix, n, ans, "", vis, di, dj)
        return ans

    Code Explanation

    This optimal solution uses direction arrays to eliminate code duplication. The di and dj arrays represent row and column offsets for each direction: Down (+1,0), Left (0,-1), Right (0,+1), Up (-1,0). The string "DLRU" maps these array indices to their corresponding direction characters. Instead of four separate if-conditions, we use a single loop that tries each direction systematically. The validation logic remains the same, but now it’s centralized in one place, making the code more maintainable and less error-prone.

    Dry Run

    Let’s trace through: matrix = [[1, 0, 0, 0], [1, 1, 0, 1], [1, 1, 0, 0], [0, 1, 1, 1]]

    graph TD
        Root["solve(0,0, move='', vis=all 0)<br/>Matrix: [[1,0,0,0],[1,1,0,1],[1,1,0,0],[0,1,1,1]]<br/>di=[+1,0,0,-1], dj=[0,-1,+1,0], dir='DLRU'<br/>Start at (0,0), target (3,3)"]
        
        %% Level 0: From (0,0), loop through 4 directions (ind=0,1,2,3)
        Root --- A["ind=0: D (Down)<br/>nexti=0+1=1, nextj=0+0=0<br/>Check: (1,0) in bounds ✓, vis[1][0]=0 ✓, mat[1][0]=1 ✓<br/>Mark vis[0][0]=1, move='D'<br/>Recurse to (1,0)"]
        Root --- B["ind=1: L (Left)<br/>nexti=0+0=0, nextj=0-1=-1<br/>Check: nextj=-1 < 0 ❌<br/>Out of bounds"]
        Root --- C["ind=2: R (Right)<br/>nexti=0+0=0, nextj=0+1=1<br/>Check: (0,1) in bounds ✓, vis[0][1]=0 ✓, mat[0][1]=0 ❌<br/>Blocked cell"]
        Root --- D["ind=3: U (Up)<br/>nexti=0-1=-1, nextj=0+0=0<br/>Check: nexti=-1 < 0 ❌<br/>Out of bounds"]
        
        %% Level 1: From (1,0), loop through 4 directions
        A --- A1["ind=0: D (Down)<br/>nexti=1+1=2, nextj=0+0=0<br/>Check: (2,0) valid, mat[2][0]=1 ✓<br/>Mark vis[1][0]=1, move='DD'<br/>Recurse to (2,0)"]
        A --- A2["ind=1: L (Left)<br/>nexti=1+0=1, nextj=0-1=-1<br/>Check: nextj=-1 < 0 ❌<br/>Out of bounds"]
        A --- A3["ind=2: R (Right)<br/>nexti=1+0=1, nextj=0+1=1<br/>Check: (1,1) valid, mat[1][1]=1 ✓<br/>Mark vis[1][0]=1, move='DR'<br/>Recurse to (1,1)"]
        A --- A4["ind=3: U (Up)<br/>nexti=1-1=0, nextj=0+0=0<br/>Check: (0,0) valid but vis[0][0]=1 ❌<br/>Already visited"]
        
        %% Level 2: From (2,0), loop through 4 directions
        A1 --- A1a["ind=0: D (Down)<br/>nexti=2+1=3, nextj=0+0=0<br/>Check: (3,0) valid but mat[3][0]=0 ❌<br/>Blocked cell"]
        A1 --- A1b["ind=1: L (Left)<br/>nexti=2+0=2, nextj=0-1=-1<br/>Check: nextj=-1 < 0 ❌<br/>Out of bounds"]
        A1 --- A1c["ind=2: R (Right)<br/>nexti=2+0=2, nextj=0+1=1<br/>Check: (2,1) valid, mat[2][1]=1 ✓<br/>Mark vis[2][0]=1, move='DDR'<br/>Recurse to (2,1)"]
        A1 --- A1d["ind=3: U (Up)<br/>nexti=2-1=1, nextj=0+0=0<br/>Check: (1,0) valid but vis[1][0]=1 ❌<br/>Already visited"]
        
        %% Level 2: From (1,1), loop through 4 directions
        A3 --- A3a["ind=0: D (Down)<br/>nexti=1+1=2, nextj=1+0=1<br/>Check: (2,1) valid, mat[2][1]=1 ✓<br/>Mark vis[1][1]=1, move='DRD'<br/>Recurse to (2,1)"]
        A3 --- A3b["ind=1: L (Left)<br/>nexti=1+0=1, nextj=1-1=0<br/>Check: (1,0) valid but vis[1][0]=1 ❌<br/>Already visited"]
        A3 --- A3c["ind=2: R (Right)<br/>nexti=1+0=1, nextj=1+1=2<br/>Check: (1,2) valid but mat[1][2]=0 ❌<br/>Blocked cell"]
        A3 --- A3d["ind=3: U (Up)<br/>nexti=1-1=0, nextj=1+0=1<br/>Check: (0,1) valid but mat[0][1]=0 ❌<br/>Blocked cell"]
        
        %% Level 3: From (2,1) via path DDR
        A1c --- A1c1["ind=0: D (Down)<br/>nexti=2+1=3, nextj=1+0=1<br/>Check: (3,1) valid, mat[3][1]=1 ✓<br/>Mark vis[2][1]=1, move='DDRD'<br/>Recurse to (3,1)"]
        A1c --- A1c2["ind=1: L (Left)<br/>nexti=2+0=2, nextj=1-1=0<br/>Check: (2,0) valid but vis[2][0]=1 ❌<br/>Already visited"]
        A1c --- A1c3["ind=2: R (Right)<br/>nexti=2+0=2, nextj=1+1=2<br/>Check: (2,2) valid but mat[2][2]=0 ❌<br/>Blocked cell"]
        A1c --- A1c4["ind=3: U (Up)<br/>nexti=2-1=1, nextj=1+0=1<br/>Check: (1,1) valid, mat[1][1]=1 ✓<br/>Mark vis[2][1]=1, move='DDRU'<br/>Recurse to (1,1)"]
        
        %% Level 3: From (2,1) via path DRD
        A3a --- A3a1["ind=0: D (Down)<br/>nexti=2+1=3, nextj=1+0=1<br/>Check: (3,1) valid, mat[3][1]=1 ✓<br/>Mark vis[2][1]=1, move='DRDD'<br/>Recurse to (3,1)"]
        A3a --- A3a2["ind=1: L (Left)<br/>nexti=2+0=2, nextj=1-1=0<br/>Check: (2,0) valid, mat[2][0]=1 ✓<br/>Mark vis[2][1]=1, move='DRDL'<br/>Recurse to (2,0)"]
        A3a --- A3a3["ind=2: R (Right)<br/>nexti=2+0=2, nextj=1+1=2<br/>Check: (2,2) valid but mat[2][2]=0 ❌<br/>Blocked cell"]
        A3a --- A3a4["ind=3: U (Up)<br/>nexti=2-1=1, nextj=1+0=1<br/>Check: (1,1) valid but vis[1][1]=1 ❌<br/>Already visited"]
        
        %% Level 4: From (3,1) via path DDRD, continue to find (3,3)
        A1c1 --- A1c1c["ind=2: R (Right)<br/>nexti=3+0=3, nextj=1+1=2<br/>Check: (3,2) valid, mat[3][2]=1 ✓<br/>Mark vis[3][1]=1, move='DDRDR'<br/>Recurse to (3,2)"]
        
        %% Level 4: From (3,1) via path DRDD, continue to find (3,3)
        A3a1 --- A3a1c["ind=2: R (Right)<br/>nexti=3+0=3, nextj=1+1=2<br/>Check: (3,2) valid, mat[3][2]=1 ✓<br/>Mark vis[3][1]=1, move='DRDDR'<br/>Recurse to (3,2)"]
        
        %% Level 5: From (3,2), reach destination (3,3)
        A1c1c --- A1c1c3["ind=2: R (Right)<br/>nexti=3+0=3, nextj=2+1=3<br/>Check: (3,3) valid, mat[3][3]=1 ✓<br/>i=3, j=3 == n-1=3 ✓<br/>Found destination!<br/>move='DDRDDR'"]
        
        A3a1c --- A3a1c3["ind=2: R (Right)<br/>nexti=3+0=3, nextj=2+1=3<br/>Check: (3,3) valid, mat[3][3]=1 ✓<br/>i=3, j=3 == n-1=3 ✓<br/>Found destination!<br/>move='DRDDRR'"]
        
        %% Success cases
        A1c1c3 --- Success1["✅ Add 'DDRDDR' to result<br/>Backtrack and unmark vis arrays"]
        A3a1c3 --- Success2["✅ Add 'DRDDRR' to result<br/>Backtrack and unmark vis arrays"]
        
        %% Final result
        Success1 --- Final["Final Result: ['DDRDDR', 'DRDDRR']"]
        Success2 --- Final
    
        %% Styling
        style Success1 fill:#90EE90
        style Success2 fill:#90EE90
        style Final fill:#90EE90
        
        style B fill:#FFB6C1
        style C fill:#FFB6C1
        style D fill:#FFB6C1
        style A2 fill:#FFB6C1
        style A4 fill:#FFB6C1
        style A1a fill:#FFB6C1
        style A1b fill:#FFB6C1
        style A1d fill:#FFB6C1
        style A3b fill:#FFB6C1
        style A3c fill:#FFB6C1
        style A3d fill:#FFB6C1
        
        style A1c1c fill:#87CEEB
        style A3a1c fill:#87CEEB
        style A1c1 fill:#87CEEB
        style A3a1 fill:#87CEEB
        
        style Root fill:#E6E6FA
    

    For detailed dry run [Click here]

    Same exploration pattern as brute force, but with cleaner code structure

    Time and Space Complexity

    • Time Complexity: O(4^(N×N)) – Same as brute force, no algorithmic improvement
    • Space Complexity: O(N×N) – Same space requirements as brute force

    Simplifying It

    This approach is like giving the rat a smart compass that automatically points to all four directions, so instead of manually checking “down, left, right, up”, the rat just follows the compass directions in order. The exploration is identical, but the implementation is much more elegant and maintainable.


    Summary

    ApproachTimeSpaceDifficultyBest For
    Brute Force (Explicit Directions)O(4^(N×N))O(N×N)MediumUnderstanding the concept
    Optimal (Direction Arrays)O(4^(N×N))O(N×N)MediumProduction code

    The optimal approach doesn’t improve time complexity but provides significant benefits:

    1. Code Maintainability – Single loop instead of 4 separate if-statements
    2. Reduced Bugs – Less code duplication means fewer places for errors
    3. Scalability – Easy to extend to 8-direction movement (add more directions to arrays)
    4. Readability – Cleaner, more professional code structure

    The key insight for Rat in a Maze is recognizing that backtracking problems often involve repetitive patterns that can be elegantly handled with arrays and loops. The direction array technique is widely used in grid-based problems like word search, number of islands, and shortest path algorithms!

    Both solutions use the same core algorithm – backtracking with DFS – but the optimal solution demonstrates how thoughtful code organization can make algorithms more maintainable without sacrificing performance.

    Join our Advance DSA COURSE

    For any changes to the article, kindly email at code@codeanddebug.in or contact us at +91-9712928220.

    Advance Recursion Medium
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Previous ArticleN-Queens | Leetcode 51 | Brute and Optimal Solution
    codeanddebug
    • Website

    Related Posts

    Data Structures & Algorithms

    N-Queens | Leetcode 51 | Brute and Optimal Solution

    22 July 2025
    Data Structures & Algorithms

    Letter Combinations of a Phone Number | Leetcode 17 | Optimal Solution in Python

    22 July 2025
    Data Structures & Algorithms

    Combination Sum III | Leetcode 216 | Optimal Solution in Python

    22 July 2025
    Add A Comment
    Leave A Reply Cancel Reply

    Categories
    • Data Structures & Algorithms (154)
      • Beginner (56)
      • Expert (38)
      • Intermediate (60)
    • Uncategorised (1)
    Recent Posts

    Rat in a Maze Problem – I | GFG Practice | 2 different solutions

    22 July 2025

    N-Queens | Leetcode 51 | Brute and Optimal Solution

    22 July 2025

    Letter Combinations of a Phone Number | Leetcode 17 | Optimal Solution in Python

    22 July 2025

    Combination Sum III | Leetcode 216 | Optimal Solution in Python

    22 July 2025

    Subset Sums | GFG Practice | Brute and Optimal Solution

    22 July 2025
    Facebook Instagram YouTube LinkedIn WhatsApp
    © 2025 Code and Debug. All rights reserved.

    Type above and press Enter to search. Press Esc to cancel.