Problem of The Day: Find Minimum Time to Reach Last Room II
Problem Statement
Intuition
The problem is to determine the minimum time required to reach the bottom-right cell of a 2D grid, given certain movement costs and conditions that alternate at each step. The idea is to use a shortest path algorithm (like Dijkstra’s) that adapts to the grid constraints and alternating movement costs.
Approach
We model this as a shortest-path problem on a grid, where each cell has a time cost constraint (moveTime[row][col]
) that affects the next move. The movement alternates between fast and slow (1 unit vs. 2 units) depending on a boolean alternate
flag, which flips every move. We use a min-heap (priority queue) to always expand the node with the least accumulated time.
- Initialize a
distance
matrix to store the minimum time to reach each cell. - Use a min-heap starting from the top-left cell
(0,0)
with time0
andalternate=True
. - For each cell, explore all 4 directions (up, down, left, right).
- If the current time is less than the time constraint
moveTime[r][c]
, wait until that time. - Update the time based on whether it is an alternate (1 unit) or not (2 units) step.
- If this new time is better than the recorded time in
distance
, update and push to the heap.
Complexity
-
Time complexity:
\(O(R \cdot C \cdot \log(R \cdot C))\)
where ( R ) is the number of rows and ( C ) is the number of columns. Each cell may be processed once in the priority queue. -
Space complexity:
\(O(R \cdot C)\)
for thedistance
,visited
, and heap storage.
Code
class Solution:
def minTimeToReach(self, moveTime: List[List[int]]) -> int:
ROWS = len(moveTime)
COLS = len(moveTime[0])
distance = [[float('inf') for _ in range(COLS)] for _ in range(ROWS)]
visited = [[False for _ in range(COLS)] for _ in range(ROWS)]
min_heap = [[0, 0, 0, True]]
distance[0][0] = 0
while min_heap:
time, row, col, alternate = heapq.heappop(min_heap)
for x, y in [(0,1),(1,0),(-1,0),(0,-1)]:
next_row = row + x
next_col = col + y
if 0 <= next_row < ROWS and 0 <= next_col < COLS and not visited[next_row][next_col]:
d = 0
if time < moveTime[next_row][next_col]:
d = moveTime[next_row][next_col] + (1 if alternate else 2)
else:
d = time + (1 if alternate else 2)
if d < distance[next_row][next_col]:
distance[next_row][next_col] = d
heapq.heappush(min_heap, [d, next_row, next_col, not alternate])
visited[next_row][next_col] = True
return distance[-1][-1]
Editorial
Approach: Shortest Path + Dijkstra
class State:
def __init__(self, x, y, dis):
self.x = x
self.y = y
self.dis = dis
def __lt__(self, other):
return self.dis < other.dis
class Solution:
def minTimeToReach(self, moveTime):
n = len(moveTime)
m = len(moveTime[0])
inf = float("inf")
d = [[inf] * m for _ in range(n)]
v = [[0] * m for _ in range(n)]
dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]
d[0][0] = 0
q = []
heapq.heappush(q, State(0, 0, 0))
while q:
s = heapq.heappop(q)
if v[s.x][s.y]:
continue
if s.x == n - 1 and s.y == m - 1:
break
v[s.x][s.y] = 1
for dx, dy in dirs:
nx, ny = s.x + dx, s.y + dy
if not (0 <= nx < n and 0 <= ny < m):
continue
dist = max(d[s.x][s.y], moveTime[nx][ny]) + (s.x + s.y) % 2 + 1
if d[nx][ny] > dist:
d[nx][ny] = dist
heapq.heappush(q, State(nx, ny, dist))
return d[n - 1][m - 1]