Check if There is a Valid Path in a Grid

MEDIUM

Description

You are given an m x n grid. Each cell of grid represents a street. The street of grid[i][j] can be:

  • 1 which means a street connecting the left cell and the right cell.
  • 2 which means a street connecting the upper cell and the lower cell.
  • 3 which means a street connecting the left cell and the lower cell.
  • 4 which means a street connecting the right cell and the lower cell.
  • 5 which means a street connecting the left cell and the upper cell.
  • 6 which means a street connecting the right cell and the upper cell.

You will initially start at the street of the upper-left cell (0, 0). A valid path in the grid is a path that starts from the upper left cell (0, 0) and ends at the bottom-right cell (m - 1, n - 1). The path should only follow the streets.

Notice that you are not allowed to change any street.

Return true if there is a valid path in the grid or false otherwise.

 

Example 1:

Input: grid = [[2,4,3],[6,5,2]]
Output: true
Explanation: As shown you can start at cell (0, 0) and visit all the cells of the grid to reach (m - 1, n - 1).

Example 2:

Input: grid = [[1,2,1],[1,2,1]]
Output: false
Explanation: As shown you the street at cell (0, 0) is not connected with any street of any other cell and you will get stuck at cell (0, 0)

Example 3:

Input: grid = [[1,1,2]]
Output: false
Explanation: You will get stuck at cell (0, 1) and you cannot reach cell (0, 2).

 

Constraints:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • 1 <= grid[i][j] <= 6

Approaches

Checkout 3 different approaches to solve Check if There is a Valid Path in a Grid. Click on different approaches to view the approach and algorithm in detail.

Recursive Depth-First Search (DFS)

This approach models the grid as a graph where each cell is a node. An edge exists between two adjacent cells if their respective streets connect to each other. The problem then becomes finding if a path exists from the source node (0, 0) to the destination node (m-1, n-1). DFS is a natural way to explore this path.

Algorithm

  • We model the grid as a graph where each cell is a node. An edge exists between two adjacent cells if their respective streets connect to each other. The problem then becomes finding if a path exists from the source node (0, 0) to the destination node (m-1, n-1).
  • We start a traversal from the cell (0, 0).
  • We use a visited boolean grid to keep track of cells that are already part of the current exploration path to avoid cycles and redundant computations.
  • The core of the approach is a recursive function, say dfs(row, col), which explores paths from the current cell (row, col).
  • Algorithm Steps:
    1. Define the possible moves for each street type. A street k allows moves in two directions. We can store this in a 3D array, e.g., moves[k-1] = {{dr1, dc1}, {dr2, dc2}}.
    2. Create a recursive function dfs(r, c, grid, visited).
    3. Base Case: If (r, c) is the destination (m-1, n-1), a path is found, return true.
    4. Mark the current cell (r, c) as visited.
    5. Get the current street type type = grid[r][c].
    6. Iterate through the two possible moves (dr, dc) for this type.
    7. For each move, calculate the neighbor's coordinates (nr, nc) = (r + dr, c + dc).
    8. Validity Checks:
      • Check if (nr, nc) is within the grid boundaries.
      • Check if (nr, nc) has been visited.
      • Crucially, check if the street at (nr, nc) connects back to (r, c). This means one of the allowed moves from (nr, nc) must be (-dr, -dc).
    9. If the move is valid, make a recursive call dfs(nr, nc, grid, visited). If this call returns true, it means a path to the destination was found, so propagate true up the call stack.
    10. The initial call is dfs(0, 0, grid, visited).
class Solution {
    // directions[street_type - 1] = {{dr1, dc1}, {dr2, dc2}}
    private int[][][] directions = {
        {{0, -1}, {0, 1}},   // 1: left-right
        {{-1, 0}, {1, 0}},   // 2: up-down
        {{0, -1}, {1, 0}},   // 3: left-down
        {{0, 1}, {1, 0}},    // 4: right-down
        {{0, -1}, {-1, 0}},  // 5: left-up
        {{0, 1}, {-1, 0}}    // 6: right-up
    };
    private int m, n;
    private boolean[][] visited;

    public boolean hasValidPath(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        visited = new boolean[m][n];
        return dfs(0, 0, grid);
    }

    private boolean dfs(int r, int c, int[][] grid) {
        if (r == m - 1 && c == n - 1) {
            return true;
        }
        visited[r][c] = true;

        int streetType = grid[r][c];
        for (int[] dir : directions[streetType - 1]) {
            int nr = r + dir[0];
            int nc = c + dir[1];

            if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited[nr][nc]) {
                // Check if the next street connects back
                int nextStreetType = grid[nr][nc];
                for (int[] backDir : directions[nextStreetType - 1]) {
                    if (nr + backDir[0] == r && nc + backDir[1] == c) {
                        if (dfs(nr, nc, grid)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
}

Complexity Analysis

Time Complexity: O(m * n). In the worst case, we visit every cell in the grid once.Space Complexity: O(m * n). This is for the `visited` array and the recursion stack. In the worst case, the recursion depth can be up to `m * n`.

Pros and Cons

Pros:
  • Conceptually straightforward and easy to implement.
  • Follows the problem's path-finding nature directly.
Cons:
  • Can lead to a StackOverflowError for very large grids where the path is long and winding, as the recursion depth could exceed the stack limit.

Code Solutions

Checking out 3 solutions in different languages for Check if There is a Valid Path in a Grid. Click on different languages to view the code.


Video Solution

Watch the video walkthrough for Check if There is a Valid Path in a Grid



Algorithms:

Depth-First SearchBreadth-First SearchUnion Find

Data Structures:

ArrayMatrix

Companies:

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.