Problem: 2532. 过桥的时间
思路
本来一上来就直接暴力做了,结果超时太狠了。之后觉得维护最小堆来获取最小值能够优化时间
解题方法
四个堆:
left_wait1:在当前 cur 时刻,左边已经在桥边等待的工人,以最低效率建堆
left_wait2:在当前 cur 时刻,左边还没有完成放下箱子的工人,以时间建堆
对于right_wait1和right_wait2也是如此。
首先,所有的工人都已在桥边等待,所以入left_wait1队列。对于 n n n个箱子,这里规定只要有工人离开left_wait1队列,就 n − − n-- n−−。
对于桥右边的判断,我们每次要先判断right_wait2中是否有新的工人能够在桥边等待了,如果可以,出堆,之后加入到right_wait1中。而对于right_wait1中的值,直接出堆,之后利用其效率和下一次排在桥边的时刻入堆。
对于桥左边的判断,与右边大致相同。
最后,我们要注意,我们这里规定的是左边工人一走,箱子数量就减一,所以并不意味着工人已经从桥的右边回来了。因此,跳出循环后,利用上述逻辑,对right_wait1和right_wait2进行出堆和入堆的判断,直到二者全部为空结束。
复杂度
-
时间复杂度: O ( n l o g k ) O(nlogk) O(nlogk)
-
空间复杂度: O ( k ) O(k) O(k)
Code
class Solution:
def findCrossingTime(self, n: int, k: int, time: List[List[int]]) -> int:
arr = sorted(time, key=lambda x: x[0] + x[2])
# left_wait 和 right_wait 分别表示左边和右边工人需要待到什么时刻会有空闲
left_wait1 = [] # 小于等于当前时间的最小堆
left_wait2 = [] # 大于当前时间的最小堆
right_wait1 = []
right_wait2 = []
cur = 0 # 记录时刻
for i in range(k):
heapq.heappush(left_wait1, (-(arr[i][0] + arr[i][2]), -i))
while n:
# 查看右边有没有等待的工人
if n and right_wait2 and cur >= right_wait2[0][0]:
_, v, i = heapq.heappop(right_wait2)
heapq.heappush(right_wait1, (v, i))
elif n and right_wait1:
v, i = heapq.heappop(right_wait1)
cur += arr[-i][2] # 从桥右边往左走
heapq.heappush(left_wait2, (cur + arr[-i][3], v, i))
elif n and left_wait2 and cur >= left_wait2[0][0]:
_, v, i = heapq.heappop(left_wait2)
heapq.heappush(left_wait1, (v, i))
elif n and left_wait1:
n -= 1
v, i = heapq.heappop(left_wait1)
cur += arr[-i][0] # 从桥左边往右走
heapq.heappush(right_wait2, (cur + arr[-i][1], v, i))
else:
cur += 1
while right_wait1 or right_wait2:
if right_wait1:
v, i = heapq.heappop(right_wait1)
cur += arr[-i][2]
if right_wait2:
if cur >= right_wait2[0][0]:
_, v, i = heapq.heappop(right_wait2)
heapq.heappush(right_wait1, (v, i))
if len(right_wait1) == 0:
cur += 1
return cur