Find Minimum Time to Reach Last Room I
Problem
There is a dungeon with n x m rooms arranged as a grid.
You are given a 2D array moveTime of size n x m, where moveTime[i][j] represents the minimum time in seconds when you can start moving to that room. You start from the room (0, 0) at time t = 0 and can move to an adjacent room. Moving between adjacent rooms takes exactly one second.
Return the minimum time to reach the room (n - 1, m - 1).
Two rooms are adjacent if they share a common wall, either horizontally or vertically.
Examples
Example 1:
Input: moveTime = [[0,4],[4,4]]
Output: 6
Explanation:
The minimum time required is 6 seconds.
* At time `t == 4`, move from room `(0, 0)` to room `(1, 0)` in one second.
* At time `t == 5`, move from room `(1, 0)` to room `(1, 1)` in one second.
Example 2:
Input: moveTime = [[0,0,0],[0,0,0]]
Output: 3
Explanation:
The minimum time required is 3 seconds.
* At time `t == 0`, move from room `(0, 0)` to room `(1, 0)` in one second.
* At time `t == 1`, move from room `(1, 0)` to room `(1, 1)` in one second.
* At time `t == 2`, move from room `(1, 1)` to room `(1, 2)` in one second.
Example 3:
Input: moveTime = [[0,1],[1,2]]
Output: 3
Constraints:
2 <= n == moveTime.length <= 502 <= m == moveTime[i].length <= 500 <= moveTime[i][j] <= 10^9
Solution
Method 1 - Using Dijkstra's algorithm
We need to find the minimum time required to reach the destination room (n-1, m-1) starting from (0, 0). This is an optimisation problem where we evaluate paths while adhering to the condition that each room has its own restriction defined by moveTime[i][j]. A room can only be entered after its restriction time has elapsed.
The grid can be seen as a graph, and moving between rooms represents edges. Using a priority queue (min-heap) is ideal for this task because we attempt to explore rooms with the smallest valid entry time first.
Approach
-
Initialisation:
- Using Dijkstra's-like algorithm, maintain a priority queue to store the current position
(x, y)and the time required to enter that room. - Create a 2D array
visitedto ensure we don't revisit rooms unnecessarily.
- Using Dijkstra's-like algorithm, maintain a priority queue to store the current position
-
Algorithm:
- Push the starting room
(0, 0)into the priority queue with time0. - For each position in the queue, evaluate its adjacent rooms (
top,bottom,left,right). - For every adjacent room, calculate the time to move to that room and ensure it meets the
moveTimeconstraint. - Update the queue with the calculated valid time only if the room hasn’t been visited yet.
- Push the starting room
-
Termination:
- Stop the algorithm when
(n-1, m-1)is reached, and return the minimum time recorded.
- Stop the algorithm when
Code
Java
class Solution {
public int minTimeToReachRoom(int[][] moveTime) {
int n = moveTime.length, m = moveTime[0].length;
boolean[][] visited = new boolean[n][m];
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> Integer.compare(a[0], b[0])); // Min-heap
pq.offer(new int[]{0, 0, 0}); // Format: {time, x, y}
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int t = cur[0], x = cur[1], y = cur[2];
if (visited[x][y]) {
continue; // Skip already visited
}
visited[x][y] = true;
if (x == n - 1 && y == m - 1) { // Destination reached
return t;
}
int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (int[] dir : directions) {
int nx = x + dir[0], ny = y + dir[1];
if (nx >= 0 && ny >= 0 && nx < n && ny < m && !visited[nx][ny]) {
int nt = Math.max(t + 1, moveTime[nx][ny]); // Wait until accessible
pq.offer(new int[]{nt, nx, ny});
}
}
}
return -1; // If unreachable
}
}
Python
class Solution:
def minTimeToReach(self, moveTime: List[List[int]]) -> int:
INF = float("inf")
n, m = len(moveTime), len(moveTime[0])
d = [[INF] * m for _ in range(n)] # Distance array
v = [[False] * m for _ in range(n)] # Visited array
d[0][0] = 0
pq = [] # Priority queue for (time, x, y)
heappush(pq, (0, 0, 0)) # Start at (0, 0) with time 0
dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)] # Movement directions
while pq:
t, x, y = heappop(pq) # Extract state with min time
if v[x][y]:
continue
v[x][y] = True
for dx, dy in dirs:
nx, ny = x + dx, y + dy
# Check bounds
if nx < 0 or ny < 0 or nx >= n or ny >= m:
continue
dist = max(d[x][y], moveTime[nx][ny]) + 1 # Calculate time for neighbour
if d[nx][ny] > dist:
d[nx][ny] = dist
heappush(pq, (dist, nx, ny))
return d[n - 1][m - 1] # Return distance to bottom-right corner
Complexity
- ⏰ Time complexity:
O(n * m log(n * m)). - The grid containsn * mcells, and processing each cell involves prioritised exploration using a heap which takes logarithmic time. - 🧺 Space complexity:
O(n * m). - Space required for visited array and grid processing.