Skip to content

Commit 45e08b6

Browse files
committed
feat: add solutions to lc problem: No.2532
No.2532.Time to Cross a Bridge
1 parent f0b42ab commit 45e08b6

File tree

6 files changed

+769
-8
lines changed

6 files changed

+769
-8
lines changed

solution/2500-2599/2532.Time to Cross a Bridge/README.md

Lines changed: 273 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,34 +85,303 @@
8585

8686
<!-- 这里可写通用的实现逻辑 -->
8787

88+
**方法一:优先队列(大小根堆) + 模拟**
89+
90+
我们先将工人按照效率从高到底排序,这样,下标越大的工人,效率越低。
91+
92+
接下来,我们用四个优先队列模拟工人的状态:
93+
94+
- `wait_in_left`:大根堆,存储当前在左岸等待的工人的下标;
95+
- `wait_in_right`:大根堆,存储当前在右岸等待的工人的下标;
96+
- `work_in_left`:小根堆,存储当前在左岸工作的工人放好箱子的时间以及工人的下标;
97+
- `work_in_right`:小根堆,存储当前在右岸工作的工人放好箱子的时间以及工人的下标。
98+
99+
初始时,所有工人都在左岸,因此 `wait_in_left` 中存储所有工人的下标。用变量 `cur` 记录当前时间。
100+
101+
然后,我们模拟整个过程。我们先判断当前时刻,`work_in_left` 是否有工人已经放好箱子,如果有,我们将工人放入 `wait_in_left` 中,然后将工人从 `work_in_left` 中移除。同理,我们再判断 `work_in_right` 是否有工人已经放好箱子,如果有,我们将工人放入 `wait_in_right` 中,然后将工人从 `work_in_right` 中移除。
102+
103+
接着,我们判断当前时刻是否有工人在左岸等待,记为 `left_to_go`,同时,我们判断当前时刻是否有工人在右岸等待,记为 `right_to_go`。如果不存在等待过岸的工人,我们直接将 `cur` 更新为下一个工人放好箱子的时间,然后继续模拟过程。
104+
105+
如果 `right_to_go``true`,我们从 `wait_in_right` 中取出一个工人,更新 `cur` 为当前时间加上该工人从右岸过左岸的时间,如果此时所有工人都已经过了右岸,我们直接将 `cur` 作为答案返回;否则,我们将该工人放入 `work_in_left` 中。
106+
107+
如果 `left_to_go``true`,我们从 `wait_in_left` 中取出一个工人,更新 `cur` 为当前时间加上该工人从左岸过右岸的时间,然后将该工人放入 `work_in_right` 中,并且将箱子数量减一。
108+
109+
循环上述过程,直到箱子数量为零,此时 `cur` 即为答案。
110+
111+
时间复杂度 $O(n \times \log k)$,空间复杂度 $O(k)$。其中 $n$ 和 $k$ 分别为工人数量和箱子数量。
112+
88113
<!-- tabs:start -->
89114

90115
### **Python3**
91116

92117
<!-- 这里可写当前语言的特殊实现逻辑 -->
93118

94119
```python
95-
120+
class Solution:
121+
def findCrossingTime(self, n: int, k: int, time: List[List[int]]) -> int:
122+
time.sort(key=lambda x: x[0] + x[2])
123+
cur = 0
124+
wait_in_left, wait_in_right = [], []
125+
work_in_left, work_in_right = [], []
126+
for i in range(k):
127+
heappush(wait_in_left, -i)
128+
while 1:
129+
while work_in_left:
130+
t, i = work_in_left[0]
131+
if t > cur:
132+
break
133+
heappop(work_in_left)
134+
heappush(wait_in_left, -i)
135+
while work_in_right:
136+
t, i = work_in_right[0]
137+
if t > cur:
138+
break
139+
heappop(work_in_right)
140+
heappush(wait_in_right, -i)
141+
left_to_go = n > 0 and wait_in_left
142+
right_to_go = bool(wait_in_right)
143+
if not left_to_go and not right_to_go:
144+
nxt = inf
145+
if work_in_left:
146+
nxt = min(nxt, work_in_left[0][0])
147+
if work_in_right:
148+
nxt = min(nxt, work_in_right[0][0])
149+
cur = nxt
150+
continue
151+
if right_to_go:
152+
i = -heappop(wait_in_right)
153+
cur += time[i][2]
154+
if n == 0 and not wait_in_right and not work_in_right:
155+
return cur
156+
heappush(work_in_left, (cur + time[i][3], i))
157+
else:
158+
i = -heappop(wait_in_left)
159+
cur += time[i][0]
160+
n -= 1
161+
heappush(work_in_right, (cur + time[i][1], i))
96162
```
97163

98164
### **Java**
99165

100166
<!-- 这里可写当前语言的特殊实现逻辑 -->
101167

102168
```java
103-
169+
class Solution {
170+
public int findCrossingTime(int n, int k, int[][] time) {
171+
int[][] t = new int[k][5];
172+
for (int i = 0; i < k; ++i) {
173+
int[] x = time[i];
174+
t[i] = new int[]{x[0], x[1], x[2], x[3], i};
175+
}
176+
Arrays.sort(t, (a, b) -> {
177+
int x = a[0] + a[2], y = b[0] + b[2];
178+
return x == y ? a[4] - b[4] : x - y;
179+
});
180+
int cur = 0;
181+
PriorityQueue<Integer> waitInLeft = new PriorityQueue<>((a, b) -> b - a);
182+
PriorityQueue<Integer> waitInRight = new PriorityQueue<>((a, b) -> b - a);
183+
PriorityQueue<int[]> workInLeft = new PriorityQueue<>((a, b) -> a[0] - b[0]);
184+
PriorityQueue<int[]> workInRight = new PriorityQueue<>((a, b) -> a[0] - b[0]);
185+
for (int i = 0; i < k; ++i) {
186+
waitInLeft.offer(i);
187+
}
188+
while (true) {
189+
while (!workInLeft.isEmpty()) {
190+
int[] p = workInLeft.peek();
191+
if (p[0] > cur) {
192+
break;
193+
}
194+
waitInLeft.offer(workInLeft.poll()[1]);
195+
}
196+
while (!workInRight.isEmpty()) {
197+
int[] p = workInRight.peek();
198+
if (p[0] > cur) {
199+
break;
200+
}
201+
waitInRight.offer(workInRight.poll()[1]);
202+
}
203+
boolean leftToGo = n > 0 && !waitInLeft.isEmpty();
204+
boolean rightToGo = !waitInRight.isEmpty();
205+
if (!leftToGo && !rightToGo) {
206+
int nxt = 1 << 30;
207+
if (!workInLeft.isEmpty()) {
208+
nxt = Math.min(nxt, workInLeft.peek()[0]);
209+
}
210+
if (!workInRight.isEmpty()) {
211+
nxt = Math.min(nxt, workInRight.peek()[0]);
212+
}
213+
cur = nxt;
214+
continue;
215+
}
216+
if (rightToGo) {
217+
int i = waitInRight.poll();
218+
cur += t[i][2];
219+
if (n == 0 && waitInRight.isEmpty() && workInRight.isEmpty()) {
220+
return cur;
221+
}
222+
workInLeft.offer(new int[] {cur + t[i][3], i});
223+
} else {
224+
int i = waitInLeft.poll();
225+
cur += t[i][0];
226+
--n;
227+
workInRight.offer(new int[] {cur + t[i][1], i});
228+
}
229+
}
230+
}
231+
}
104232
```
105233

106234
### **C++**
107235

108236
```cpp
109-
237+
class Solution {
238+
public:
239+
int findCrossingTime(int n, int k, vector<vector<int>>& time) {
240+
using pii = pair<int, int>;
241+
for (int i = 0; i < k; ++i) {
242+
time[i].push_back(i);
243+
}
244+
sort(time.begin(), time.end(), [](auto& a, auto& b) {
245+
int x = a[0] + a[2], y = b[0] + b[2];
246+
return x == y ? a[4] < b[4] : x < y;
247+
});
248+
int cur = 0;
249+
priority_queue<int> waitInLeft, waitInRight;
250+
priority_queue<pii, vector<pii>, greater<pii>> workInLeft, workInRight;
251+
for (int i = 0; i < k; ++i) {
252+
waitInLeft.push(i);
253+
}
254+
while (true) {
255+
while (!workInLeft.empty()) {
256+
auto [t, i] = workInLeft.top();
257+
if (t > cur) {
258+
break;
259+
}
260+
workInLeft.pop();
261+
waitInLeft.push(i);
262+
}
263+
while (!workInRight.empty()) {
264+
auto [t, i] = workInRight.top();
265+
if (t > cur) {
266+
break;
267+
}
268+
workInRight.pop();
269+
waitInRight.push(i);
270+
}
271+
bool leftToGo = n > 0 && !waitInLeft.empty();
272+
bool rightToGo = !waitInRight.empty();
273+
if (!leftToGo && !rightToGo) {
274+
int nxt = 1 << 30;
275+
if (!workInLeft.empty()) {
276+
nxt = min(nxt, workInLeft.top().first);
277+
}
278+
if (!workInRight.empty()) {
279+
nxt = min(nxt, workInRight.top().first);
280+
}
281+
cur = nxt;
282+
continue;
283+
}
284+
if (rightToGo) {
285+
int i = waitInRight.top();
286+
waitInRight.pop();
287+
cur += time[i][2];
288+
if (n == 0 && waitInRight.empty() && workInRight.empty()) {
289+
return cur;
290+
}
291+
workInLeft.push({cur + time[i][3], i});
292+
} else {
293+
int i = waitInLeft.top();
294+
waitInLeft.pop();
295+
cur += time[i][0];
296+
--n;
297+
workInRight.push({cur + time[i][1], i});
298+
}
299+
}
300+
}
301+
};
110302
```
111303
112304
### **Go**
113305
114306
```go
115-
307+
func findCrossingTime(n int, k int, time [][]int) int {
308+
sort.SliceStable(time, func(i, j int) bool { return time[i][0]+time[i][2] < time[j][0]+time[j][2] })
309+
waitInLeft := hp{}
310+
waitInRight := hp{}
311+
workInLeft := hp2{}
312+
workInRight := hp2{}
313+
for i := range time {
314+
heap.Push(&waitInLeft, i)
315+
}
316+
cur := 0
317+
for {
318+
for len(workInLeft) > 0 {
319+
if workInLeft[0].t > cur {
320+
break
321+
}
322+
heap.Push(&waitInLeft, heap.Pop(&workInLeft).(pair).i)
323+
}
324+
for len(workInRight) > 0 {
325+
if workInRight[0].t > cur {
326+
break
327+
}
328+
heap.Push(&waitInRight, heap.Pop(&workInRight).(pair).i)
329+
}
330+
leftToGo := n > 0 && waitInLeft.Len() > 0
331+
rightToGo := waitInRight.Len() > 0
332+
if !leftToGo && !rightToGo {
333+
nxt := 1 << 30
334+
if len(workInLeft) > 0 {
335+
nxt = min(nxt, workInLeft[0].t)
336+
}
337+
if len(workInRight) > 0 {
338+
nxt = min(nxt, workInRight[0].t)
339+
}
340+
cur = nxt
341+
continue
342+
}
343+
if rightToGo {
344+
i := heap.Pop(&waitInRight).(int)
345+
cur += time[i][2]
346+
if n == 0 && waitInRight.Len() == 0 && len(workInRight) == 0 {
347+
return cur
348+
}
349+
heap.Push(&workInLeft, pair{cur + time[i][3], i})
350+
} else {
351+
i := heap.Pop(&waitInLeft).(int)
352+
cur += time[i][0]
353+
n--
354+
heap.Push(&workInRight, pair{cur + time[i][1], i})
355+
}
356+
}
357+
}
358+
359+
type hp struct{ sort.IntSlice }
360+
361+
func (h hp) Less(i, j int) bool { return h.IntSlice[i] > h.IntSlice[j] }
362+
func (h *hp) Push(v interface{}) { h.IntSlice = append(h.IntSlice, v.(int)) }
363+
func (h *hp) Pop() interface{} {
364+
a := h.IntSlice
365+
v := a[len(a)-1]
366+
h.IntSlice = a[:len(a)-1]
367+
return v
368+
}
369+
370+
type pair struct{ t, i int }
371+
type hp2 []pair
372+
373+
func (h hp2) Len() int { return len(h) }
374+
func (h hp2) Less(i, j int) bool { return h[i].t < h[j].t }
375+
func (h hp2) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
376+
func (h *hp2) Push(v interface{}) { *h = append(*h, v.(pair)) }
377+
func (h *hp2) Pop() interface{} { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
378+
379+
func min(a, b int) int {
380+
if a < b {
381+
return a
382+
}
383+
return b
384+
}
116385
```
117386

118387
### **...**

0 commit comments

Comments
 (0)