Check if There is a Valid Path in a Grid

medium graph dfs bfs matrix

Problem

You are given an m×n grid where each cell holds a street number from 1 to 6. Each street type fixes exactly two openings on its sides: 1 connects left↔right, 2 connects up↔down, 3 connects left↔down, 4 connects right↔down, 5 connects left↔up, and 6 connects right↔up. You may walk from a cell to a neighbor only when both tiles have an opening facing each other. Starting at the upper-left cell (0, 0), decide whether a valid path of connected streets reaches the lower-right cell (m−1, n−1).

Inputgrid = [[2,4,3],[6,5,2]]
Outputtrue
The streets connect (0,0)→(1,0)→(1,1)→(0,1)→(0,2)→(1,2), so the target is reachable.

def has_valid_path(grid):
    m, n = len(grid), len(grid[0])
    # opening directions per street: L,R,U,D as (dr,dc)
    ports = {1: [(0,-1),(0,1)], 2: [(-1,0),(1,0)], 3: [(0,-1),(1,0)],
             4: [(0,1),(1,0)], 5: [(0,-1),(-1,0)], 6: [(0,1),(-1,0)]}
    seen = [[False]*n for _ in range(m)]
    stack = [(0, 0)]
    seen[0][0] = True
    while stack:
        r, c = stack.pop()
        if r == m - 1 and c == n - 1:
            return True
        for dr, dc in ports[grid[r][c]]:
            nr, nc = r + dr, c + dc
            if 0 <= nr < m and 0 <= nc < n and not seen[nr][nc] \
               and (-dr, -dc) in ports[grid[nr][nc]]:
                seen[nr][nc] = True
                stack.append((nr, nc))
    return False
function hasValidPath(grid) {
  const m = grid.length, n = grid[0].length;
  const ports = {1:[[0,-1],[0,1]], 2:[[-1,0],[1,0]], 3:[[0,-1],[1,0]],
                 4:[[0,1],[1,0]], 5:[[0,-1],[-1,0]], 6:[[0,1],[-1,0]]};
  const seen = Array.from({length: m}, () => Array(n).fill(false));
  const stack = [[0, 0]];
  seen[0][0] = true;
  while (stack.length) {
    const [r, c] = stack.pop();
    if (r === m - 1 && c === n - 1) return true;
    for (const [dr, dc] of ports[grid[r][c]]) {
      const nr = r + dr, nc = c + dc;
      if (nr >= 0 && nr < m && nc >= 0 && nc < n && !seen[nr][nc]
          && ports[grid[nr][nc]].some(p => p[0] === -dr && p[1] === -dc)) {
        seen[nr][nc] = true;
        stack.push([nr, nc]);
      }
    }
  }
  return false;
}
class Solution {
    public boolean hasValidPath(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int[][][] ports = {{}, {{0,-1},{0,1}}, {{-1,0},{1,0}}, {{0,-1},{1,0}},
                           {{0,1},{1,0}}, {{0,-1},{-1,0}}, {{0,1},{-1,0}}};
        boolean[][] seen = new boolean[m][n];
        Deque<int[]> stack = new ArrayDeque<>();
        stack.push(new int[]{0, 0});
        seen[0][0] = true;
        while (!stack.isEmpty()) {
            int[] cur = stack.pop();
            int r = cur[0], c = cur[1];
            if (r == m - 1 && c == n - 1) return true;
            for (int[] d : ports[grid[r][c]]) {
                int nr = r + d[0], nc = c + d[1];
                if (nr >= 0 && nr < m && nc >= 0 && nc < n && !seen[nr][nc]
                    && connects(ports[grid[nr][nc]], -d[0], -d[1])) {
                    seen[nr][nc] = true;
                    stack.push(new int[]{nr, nc});
                }
            }
        }
        return false;
    }
    private boolean connects(int[][] p, int dr, int dc) {
        for (int[] d : p) if (d[0] == dr && d[1] == dc) return true;
        return false;
    }
}
bool hasValidPath(vector<vector<int>>& grid) {
    int m = grid.size(), n = grid[0].size();
    vector<vector<pair<int,int>>> ports = {{}, {{0,-1},{0,1}}, {{-1,0},{1,0}},
        {{0,-1},{1,0}}, {{0,1},{1,0}}, {{0,-1},{-1,0}}, {{0,1},{-1,0}}};
    vector<vector<bool>> seen(m, vector<bool>(n, false));
    vector<pair<int,int>> stack = {{0, 0}};
    seen[0][0] = true;
    while (!stack.empty()) {
        auto [r, c] = stack.back(); stack.pop_back();
        if (r == m - 1 && c == n - 1) return true;
        for (auto [dr, dc] : ports[grid[r][c]]) {
            int nr = r + dr, nc = c + dc;
            if (nr < 0 || nr >= m || nc < 0 || nc >= n || seen[nr][nc]) continue;
            for (auto [pr, pc] : ports[grid[nr][nc]])
                if (pr == -dr && pc == -dc) {
                    seen[nr][nc] = true;
                    stack.push_back({nr, nc});
                }
        }
    }
    return false;
}
Time: O(m·n) Space: O(m·n)