Minimum Time to Visit a Cell In a Grid

hard dijkstra grid

Problem

You get an m × n matrix grid of non-negative integers, where grid[r][c] is the earliest second at which you are allowed to step into cell (r, c). You start in the top-left cell at second 0, every move to an edge-adjacent cell takes exactly 1 second, and you may revisit cells — but you can never stand still. Return the minimum second at which you can reach the bottom-right cell, or −1 if it is impossible.

Since waiting in place is forbidden, the only way to kill time is to bounce between two adjacent cells, and each round trip costs exactly 2 seconds — so the parity of your arrival times is locked in.

Inputgrid = [[0,1,3,2],[5,1,2,5],[4,3,8,6]]
Output7
Walk (0,0)→(0,1)→(1,1)→(1,2), bounce back to (1,1) and return, so (1,3) is entered at second 6 (≥ 5) and (2,3) at second 7 (≥ 6).

import heapq

def minimum_time(grid):
    if grid[0][1] > 1 and grid[1][0] > 1:
        return -1                          # locked in at the start
    m, n = len(grid), len(grid[0])
    dist = [[float("inf")] * n for _ in range(m)]
    seen = [[False] * n for _ in range(m)]
    dist[0][0] = 0
    pq = [(0, 0, 0)]                       # (time, row, col)
    while pq:
        t, r, c = heapq.heappop(pq)
        if seen[r][c]:
            continue
        seen[r][c] = True
        if r == m - 1 and c == n - 1:
            return t
        for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
            nr, nc = r + dr, c + dc
            if not (0 <= nr < m and 0 <= nc < n) or seen[nr][nc]:
                continue
            nt = t + 1
            if nt < grid[nr][nc]:          # too early: bounce to wait
                nt = grid[nr][nc] + (grid[nr][nc] - nt) % 2
            if nt < dist[nr][nc]:
                dist[nr][nc] = nt
                heapq.heappush(pq, (nt, nr, nc))
    return -1
function minimumTime(grid) {
  if (grid[0][1] > 1 && grid[1][0] > 1) return -1;
  const m = grid.length, n = grid[0].length;
  const dist = Array.from({ length: m }, () => Array(n).fill(Infinity));
  const seen = Array.from({ length: m }, () => Array(n).fill(false));
  dist[0][0] = 0;
  const pq = [[0, 0, 0]];                 // [time, row, col]
  const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]];
  while (pq.length) {
    pq.sort((a, b) => a[0] - b[0]);       // smallest time first
    const [t, r, c] = pq.shift();
    if (seen[r][c]) continue;
    seen[r][c] = true;
    if (r === m - 1 && c === n - 1) return t;
    for (const [dr, dc] of dirs) {
      const nr = r + dr, nc = c + dc;
      if (nr < 0 || nr >= m || nc < 0 || nc >= n || seen[nr][nc]) continue;
      let nt = t + 1;
      if (nt < grid[nr][nc]) nt = grid[nr][nc] + ((grid[nr][nc] - nt) % 2);
      if (nt < dist[nr][nc]) {
        dist[nr][nc] = nt;
        pq.push([nt, nr, nc]);
      }
    }
  }
  return -1;
}
int minimumTime(int[][] grid) {
    if (grid[0][1] > 1 && grid[1][0] > 1) return -1;
    int m = grid.length, n = grid[0].length;
    int[][] dist = new int[m][n];
    for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
    boolean[][] seen = new boolean[m][n];
    dist[0][0] = 0;
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    pq.add(new int[]{0, 0, 0});           // {time, row, col}
    int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    while (!pq.isEmpty()) {
        int[] cur = pq.poll();
        int t = cur[0], r = cur[1], c = cur[2];
        if (seen[r][c]) continue;
        seen[r][c] = true;
        if (r == m - 1 && c == n - 1) return t;
        for (int[] d : dirs) {
            int nr = r + d[0], nc = c + d[1];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n || seen[nr][nc]) continue;
            int nt = t + 1;
            if (nt < grid[nr][nc]) nt = grid[nr][nc] + (grid[nr][nc] - nt) % 2;
            if (nt < dist[nr][nc]) {
                dist[nr][nc] = nt;
                pq.add(new int[]{nt, nr, nc});
            }
        }
    }
    return -1;
}
int minimumTime(vector<vector<int>>& grid) {
    if (grid[0][1] > 1 && grid[1][0] > 1) return -1;
    int m = grid.size(), n = grid[0].size();
    vector<vector<int>> dist(m, vector<int>(n, INT_MAX));
    vector<vector<bool>> seen(m, vector<bool>(n, false));
    dist[0][0] = 0;
    priority_queue<array<int,3>, vector<array<int,3>>, greater<>> pq;
    pq.push({0, 0, 0});                   // {time, row, col}
    int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    while (!pq.empty()) {
        auto [t, r, c] = pq.top(); pq.pop();
        if (seen[r][c]) continue;
        seen[r][c] = true;
        if (r == m - 1 && c == n - 1) return t;
        for (auto& d : dirs) {
            int nr = r + d[0], nc = c + d[1];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n || seen[nr][nc]) continue;
            int nt = t + 1;
            if (nt < grid[nr][nc]) nt = grid[nr][nc] + (grid[nr][nc] - nt) % 2;
            if (nt < dist[nr][nc]) {
                dist[nr][nc] = nt;
                pq.push({nt, nr, nc});
            }
        }
    }
    return -1;
}
Time: O(m·n log(m·n)) Space: O(m·n)