Find Minimum Time to Reach Last Room I

medium graph dijkstra shortest path heap

Problem

A dungeon is an n × m grid of rooms. moveTime[i][j] is the earliest second at which room (i, j) opens and may be entered. You start at (0, 0) at time t = 0; each move to an orthogonally adjacent room takes exactly one second. To step into a neighbor you must first wait until it opens, so leaving at time t you arrive at max(t, moveTime[neighbor]) + 1. Return the minimum time to reach (n − 1, m − 1).

InputmoveTime = [[0,4],[4,4]]
Output6
Wait until t = 4, step to (1,0) arriving at t = 5, then step to (1,1) arriving at t = 6.

import heapq

def minTimeToReach(moveTime):
    n, m = len(moveTime), len(moveTime[0])
    INF = float("inf")
    dist = [[INF] * m for _ in range(n)]
    dist[0][0] = 0
    pq = [(0, 0, 0)]                      # (time, row, col)
    while pq:
        t, r, c = heapq.heappop(pq)
        if t > dist[r][c]:               # stale entry, skip
            continue
        if r == n - 1 and c == m - 1:    # reached the last room
            return t
        for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < n and 0 <= nc < m:
                nt = max(t, moveTime[nr][nc]) + 1   # wait, then move
                if nt < dist[nr][nc]:
                    dist[nr][nc] = nt
                    heapq.heappush(pq, (nt, nr, nc))
    return dist[n - 1][m - 1]
function minTimeToReach(moveTime) {
  const n = moveTime.length, m = moveTime[0].length;
  const dist = Array.from({ length: n }, () => Array(m).fill(Infinity));
  dist[0][0] = 0;
  const pq = [[0, 0, 0]];                 // [time, row, col] min-heap
  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 (t > dist[r][c]) continue;          // stale entry, skip
    if (r === n - 1 && c === m - 1) return t;
    for (const [dr, dc] of dirs) {
      const nr = r + dr, nc = c + dc;
      if (nr < 0 || nr >= n || nc < 0 || nc >= m) continue;
      const nt = Math.max(t, moveTime[nr][nc]) + 1;  // wait, then move
      if (nt < dist[nr][nc]) {
        dist[nr][nc] = nt;
        pq.push([nt, nr, nc]);
      }
    }
  }
  return dist[n - 1][m - 1];
}
int minTimeToReach(int[][] moveTime) {
    int n = moveTime.length, m = moveTime[0].length;
    int[][] dist = new int[n][m];
    for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
    dist[0][0] = 0;
    // min-heap on time: {time, row, col}
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    pq.offer(new int[]{0, 0, 0});
    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 (t > dist[r][c]) continue;          // stale entry, skip
        if (r == n - 1 && c == m - 1) return t;
        for (int[] d : dirs) {
            int nr = r + d[0], nc = c + d[1];
            if (nr < 0 || nr >= n || nc < 0 || nc >= m) continue;
            int nt = Math.max(t, moveTime[nr][nc]) + 1;  // wait, then move
            if (nt < dist[nr][nc]) {
                dist[nr][nc] = nt;
                pq.offer(new int[]{nt, nr, nc});
            }
        }
    }
    return dist[n - 1][m - 1];
}
int minTimeToReach(vector<vector<int>>& moveTime) {
    int n = moveTime.size(), m = moveTime[0].size();
    vector<vector<int>> dist(n, vector<int>(m, INT_MAX));
    dist[0][0] = 0;
    // min-heap of {time, row, col}
    priority_queue<array<int,3>, vector<array<int,3>>, greater<>> pq;
    pq.push({0, 0, 0});
    int dirs[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
    while (!pq.empty()) {
        auto [t, r, c] = pq.top(); pq.pop();
        if (t > dist[r][c]) continue;          // stale entry, skip
        if (r == n - 1 && c == m - 1) return t;
        for (auto& d : dirs) {
            int nr = r + d[0], nc = c + d[1];
            if (nr < 0 || nr >= n || nc < 0 || nc >= m) continue;
            int nt = max(t, moveTime[nr][nc]) + 1;  // wait, then move
            if (nt < dist[nr][nc]) {
                dist[nr][nc] = nt;
                pq.push({nt, nr, nc});
            }
        }
    }
    return dist[n - 1][m - 1];
}
Time: O(n·m·log(n·m)) Space: O(n·m)