3342.到达最后一个房间的最少时间 II
Dijkstra, https://leetcode.cn/problems/find-minimum-time-to-reach-last-room-ii/
有一个地窖,地窖中有 n x m 个房间,它们呈网格状排布。
给你一个大小为 n x m 的二维数组 moveTime ,其中 moveTime[i][j] 表示在这个时刻 以后 你才可以 开始 往这个房间 移动 。你在时刻 t = 0 时从房间 (0, 0) 出发,每次可以移动到 相邻 的一个房间。在 相邻 房间之间移动需要的时间为:第一次花费 1 秒,第二次花费 2 秒,第三次花费 1 秒,第四次花费 2 秒……如此 往复 。
请你返回到达房间 (n - 1, m - 1) 所需要的 最少 时间。
如果两个房间有一条公共边(可以是水平的也可以是竖直的),那么我们称这两个房间是 相邻 的。
示例 1:
输入:moveTime = [[0,4],[4,4]]
输出:7
解释:
需要花费的最少时间为 7 秒。
- 在时刻
t == 4,从房间(0, 0)移动到房间(1, 0),花费 1 秒。 - 在时刻
t == 5,从房间(1, 0)移动到房间(1, 1),花费 2 秒。
示例 2:
输入:moveTime = [[0,0,0,0],[0,0,0,0]]
输出:6
解释:
需要花费的最少时间为 6 秒。
- 在时刻
t == 0,从房间(0, 0)移动到房间(1, 0),花费 1 秒。 - 在时刻
t == 1,从房间(1, 0)移动到房间(1, 1),花费 2 秒。 - 在时刻
t == 3,从房间(1, 1)移动到房间(1, 2),花费 1 秒。 - 在时刻
t == 4,从房间(1, 2)移动到房间(1, 3),花费 2 秒。
示例 3:
输入:moveTime = [[0,1],[1,2]]
输出:4
提示:
2 <= n == moveTime.length <= 7502 <= m == moveTime[i].length <= 7500 <= moveTime[i][j] <= 10^9
✅ 思路
需要使用一个 优先队列(最小堆) 来实现 Dijkstra 算法,并且每个状态需要保存三个信息:
time: 当前时间r,c: 当前所在的坐标step: 当前是第几步(用于判断下一步是 1 秒还是 2 秒)
并且访问数组应该是一个二维数组 dist[r][c][2],表示到达 (r, c) 位置时:
- 如果是从奇数步到达的最短时间;
- 如果是从偶数步到达的最短时间;
✅ 代码如下:
python
import heapq
from typing import List
class Solution:
def minTimeToReach(self, moveTime: List[List[int]]) -> int:
n, m = len(moveTime), len(moveTime[0])
# dist[i][j][0 or 1]: 到达 (i,j) 时如果是奇数步/偶数步的最早时间
dist = [[[float('inf')] * 2 for _ in range(m)] for _ in range(n)]
dist[0][0][0] = 0 # 起点从第0步开始(视为奇数跳)
# 堆中保存 (当前时间, 行, 列, 步数奇偶性)
pq = [(0, 0, 0, 0)]
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
while pq:
time, r, c, step = heapq.heappop(pq)
if r == n - 1 and c == m - 1:
return time
if dist[r][c][step % 2] < time: # 优化
continue
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < n and 0 <= nc < m:
next_step = step + 1
cost = 1 if next_step % 2 == 1 else 2
arrival_time = max(time, moveTime[nr][nc]) + cost
if arrival_time < dist[nr][nc][next_step % 2]:
dist[nr][nc][next_step % 2] = arrival_time
heapq.heappush(pq, (arrival_time, nr, nc, next_step))
return -1
if __name__ == "__main__":
sol = Solution()
print(sol.minTimeToReach([[0,4],[4,4]])) # 输出应为 7
print(sol.minTimeToReach([[0,0,0,0],[0,0,0,0]])) # 输出应为 6
print(sol.minTimeToReach([[0,1],[1,2]])) # 输出应为 4⏱️ 时间复杂度分析:
- 每个节点最多被访问两次(奇数步和偶数步),因此总共有
n * m * 2个状态。 - 使用堆优化的 Dijkstra 算法,总时间复杂度为
O(n * m * log(n * m)),在n, m <= 750下是可以通过的。