Skip to content

Commit 2981736

Browse files
authored
feat: add solutions to lc problem: No.3506 (#4318)
No.3506.Find Time Required to Eliminate Bacterial Strains II
1 parent a79dce4 commit 2981736

File tree

11 files changed

+311
-17
lines changed

11 files changed

+311
-17
lines changed

solution/1100-1199/1199.Minimum Time to Build Blocks/README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ tags:
7777

7878
### 方法一:贪心 + 优先队列(小根堆)
7979

80-
先考虑只有一个街区的情况,此时不需要分裂工人,直接让他去建造街区,时间花费为 $block[0]$。
80+
先考虑只有一个街区的情况,此时不需要分裂工人,直接让他去建造街区,时间花费为 $\textit{block}[0]$。
8181

82-
如果有两个街区,此时需要把工人分裂为两个,然后让他们分别去建造街区,时间花费为 $split + \max(block[0], block[1])$。
82+
如果有两个街区,此时需要把工人分裂为两个,然后让他们分别去建造街区,时间花费为 $\textit{split} + \max(\textit{block}[0], \textit{block}[1])$。
8383

8484
如果有超过两个街区,此时每一步都需要考虑将几个工人进行分裂,正向思维不好处理。
8585

86-
我们不妨采用逆向思维,不分裂工人,而是将街区进行合并。我们选取任意两个街区 $i$, $j$ 进行合并,建造一个新的街区的时间为 $split + \max(block[i], block[j])$。
86+
我们不妨采用逆向思维,不分裂工人,而是将街区进行合并。我们选取任意两个街区 $i$, $j$ 进行合并,建造一个新的街区的时间为 $\textit{split} + \max(\textit{block}[i], \textit{block}[j])$。
8787

8888
为了让耗时长的街区尽可能少参与到合并中,我们可以每次贪心地选取耗时最小的两个街区进行合并。因此,我们可以维护一个小根堆,每次取出最小的两个街区进行合并,直到只剩下一个街区。最后剩下的这个街区的建造时间就是答案。
8989

@@ -176,9 +176,9 @@ function minBuildTime(blocks: number[], split: number): number {
176176
}
177177
while (pq.size() > 1) {
178178
pq.dequeue()!;
179-
pq.enqueue(pq.dequeue()!.element + split);
179+
pq.enqueue(pq.dequeue()! + split);
180180
}
181-
return pq.dequeue()!.element;
181+
return pq.dequeue()!;
182182
}
183183
```
184184

solution/1100-1199/1199.Minimum Time to Build Blocks/README_EN.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ function minBuildTime(blocks: number[], split: number): number {
174174
}
175175
while (pq.size() > 1) {
176176
pq.dequeue()!;
177-
pq.enqueue(pq.dequeue()!.element + split);
177+
pq.enqueue(pq.dequeue()! + split);
178178
}
179-
return pq.dequeue()!.element;
179+
return pq.dequeue()!;
180180
}
181181
```
182182

solution/1100-1199/1199.Minimum Time to Build Blocks/Solution.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function minBuildTime(blocks: number[], split: number): number {
55
}
66
while (pq.size() > 1) {
77
pq.dequeue()!;
8-
pq.enqueue(pq.dequeue()!.element + split);
8+
pq.enqueue(pq.dequeue()! + split);
99
}
10-
return pq.dequeue()!.element;
10+
return pq.dequeue()!;
1111
}

solution/3500-3599/3506.Find Time Required to Eliminate Bacterial Strains II/README.md

+108-4
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,136 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3500-3599/3506.Fi
8484

8585
<!-- solution:start -->
8686

87-
### 方法一
87+
### 方法一:贪心 + 优先队列(小根堆)
88+
89+
先考虑只有一种细菌的情况,此时不需要分裂白细胞,直接让他去消灭细菌,时间花费为 $\textit{timeSeq}[0]$。
90+
91+
如果有两种细菌,此时需要把白细胞分裂为两种,然后让它们分别去消灭细菌,时间花费为 $\textit{splitTime} + \max(\textit{timeSeq}[0], \textit{timeSeq}[1])$。
92+
93+
如果有超过两种细菌,此时每一步都需要考虑将几个白细胞进行分裂,正向思维不好处理。
94+
95+
我们不妨采用逆向思维,不分裂白细胞,而是将细菌进行合并。我们选取任意两种细菌 $i$, $j$ 进行合并,合并成一种新的细菌的时间为 $\textit{splitTime} + \max(\textit{timeSeq}[i], \textit{timeSeq}[j])$。
96+
97+
为了让耗时长的细菌尽可能少参与到合并中,我们可以每次贪心地选取耗时最小的两种细菌进行合并。因此,我们可以维护一个小根堆,每次取出最小的两种细菌进行合并,直到只剩下一种细菌。最后剩下的这个细菌的消灭时间就是答案。
98+
99+
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为细菌的数量。
88100

89101
<!-- tabs:start -->
90102

91103
#### Python3
92104

93105
```python
94-
106+
class Solution:
107+
def minEliminationTime(self, timeReq: List[int], splitTime: int) -> int:
108+
heapify(timeReq)
109+
while len(timeReq) > 1:
110+
heappop(timeReq)
111+
heappush(timeReq, heappop(timeReq) + splitTime)
112+
return timeReq[0]
95113
```
96114

97115
#### Java
98116

99117
```java
100-
118+
class Solution {
119+
public long minEliminationTime(int[] timeReq, int splitTime) {
120+
PriorityQueue<Long> q = new PriorityQueue<>();
121+
for (int x : timeReq) {
122+
q.offer((long) x);
123+
}
124+
while (q.size() > 1) {
125+
q.poll();
126+
q.offer(q.poll() + splitTime);
127+
}
128+
return q.poll();
129+
}
130+
}
101131
```
102132

103133
#### C++
104134

105135
```cpp
106-
136+
class Solution {
137+
public:
138+
long long minEliminationTime(vector<int>& timeReq, int splitTime) {
139+
using ll = long long;
140+
priority_queue<ll, vector<ll>, greater<ll>> pq;
141+
for (int v : timeReq) {
142+
pq.push(v);
143+
}
144+
while (pq.size() > 1) {
145+
pq.pop();
146+
ll x = pq.top();
147+
pq.pop();
148+
pq.push(x + splitTime);
149+
}
150+
return pq.top();
151+
}
152+
};
107153
```
108154
109155
#### Go
110156
111157
```go
158+
func minEliminationTime(timeReq []int, splitTime int) int64 {
159+
pq := hp{}
160+
for _, v := range timeReq {
161+
heap.Push(&pq, v)
162+
}
163+
for pq.Len() > 1 {
164+
heap.Pop(&pq)
165+
heap.Push(&pq, heap.Pop(&pq).(int)+splitTime)
166+
}
167+
return int64(pq.IntSlice[0])
168+
}
169+
170+
type hp struct{ sort.IntSlice }
171+
172+
func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
173+
func (h *hp) Pop() any {
174+
a := h.IntSlice
175+
v := a[len(a)-1]
176+
h.IntSlice = a[:len(a)-1]
177+
return v
178+
}
179+
```
180+
181+
#### TypeScript
182+
183+
```ts
184+
function minEliminationTime(timeReq: number[], splitTime: number): number {
185+
const pq = new MinPriorityQueue();
186+
for (const b of timeReq) {
187+
pq.enqueue(b);
188+
}
189+
while (pq.size() > 1) {
190+
pq.dequeue()!;
191+
pq.enqueue(pq.dequeue()! + splitTime);
192+
}
193+
return pq.dequeue()!;
194+
}
195+
```
112196

197+
#### Rust
198+
199+
```rust
200+
use std::cmp::Reverse;
201+
use std::collections::BinaryHeap;
202+
203+
impl Solution {
204+
pub fn min_elimination_time(time_req: Vec<i32>, split_time: i32) -> i64 {
205+
let mut pq = BinaryHeap::new();
206+
for x in time_req {
207+
pq.push(Reverse(x as i64));
208+
}
209+
while pq.len() > 1 {
210+
pq.pop();
211+
let merged = pq.pop().unwrap().0 + split_time as i64;
212+
pq.push(Reverse(merged));
213+
}
214+
pq.pop().unwrap().0
215+
}
216+
}
113217
```
114218

115219
<!-- tabs:end -->

solution/3500-3599/3506.Find Time Required to Eliminate Bacterial Strains II/README_EN.md

+108-4
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,136 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3500-3599/3506.Fi
8484

8585
<!-- solution:start -->
8686

87-
### Solution 1
87+
### Solution 1: Greedy + Priority Queue (Min-Heap)
88+
89+
First, consider the case where there is only one type of bacteria. In this case, there is no need to split the white blood cell (WBC); it can directly eliminate the bacteria, and the time cost is $\textit{timeSeq}[0]$.
90+
91+
If there are two types of bacteria, the WBC needs to split into two, and each WBC eliminates one type of bacteria. The time cost is $\textit{splitTime} + \max(\textit{timeSeq}[0], \textit{timeSeq}[1])$.
92+
93+
If there are more than two types of bacteria, at each step, we need to consider splitting the WBCs into multiple cells, which is difficult to handle with a forward-thinking approach.
94+
95+
Instead, we can adopt a reverse-thinking approach: instead of splitting the WBCs, we merge the bacteria. We select any two types of bacteria $i$ and $j$ to merge into a new type of bacteria. The time cost for this merge is $\textit{splitTime} + \max(\textit{timeSeq}[i], \textit{timeSeq}[j])$.
96+
97+
To minimize the involvement of bacteria with long elimination times in the merging process, we can greedily select the two bacteria with the smallest elimination times for merging at each step. Therefore, we can maintain a min-heap, repeatedly extracting the two bacteria with the smallest elimination times and merging them until only one type of bacteria remains. The elimination time of this final bacteria is the answer.
98+
99+
The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$, where $n$ is the number of bacteria.
88100

89101
<!-- tabs:start -->
90102

91103
#### Python3
92104

93105
```python
94-
106+
class Solution:
107+
def minEliminationTime(self, timeReq: List[int], splitTime: int) -> int:
108+
heapify(timeReq)
109+
while len(timeReq) > 1:
110+
heappop(timeReq)
111+
heappush(timeReq, heappop(timeReq) + splitTime)
112+
return timeReq[0]
95113
```
96114

97115
#### Java
98116

99117
```java
100-
118+
class Solution {
119+
public long minEliminationTime(int[] timeReq, int splitTime) {
120+
PriorityQueue<Long> q = new PriorityQueue<>();
121+
for (int x : timeReq) {
122+
q.offer((long) x);
123+
}
124+
while (q.size() > 1) {
125+
q.poll();
126+
q.offer(q.poll() + splitTime);
127+
}
128+
return q.poll();
129+
}
130+
}
101131
```
102132

103133
#### C++
104134

105135
```cpp
106-
136+
class Solution {
137+
public:
138+
long long minEliminationTime(vector<int>& timeReq, int splitTime) {
139+
using ll = long long;
140+
priority_queue<ll, vector<ll>, greater<ll>> pq;
141+
for (int v : timeReq) {
142+
pq.push(v);
143+
}
144+
while (pq.size() > 1) {
145+
pq.pop();
146+
ll x = pq.top();
147+
pq.pop();
148+
pq.push(x + splitTime);
149+
}
150+
return pq.top();
151+
}
152+
};
107153
```
108154
109155
#### Go
110156
111157
```go
158+
func minEliminationTime(timeReq []int, splitTime int) int64 {
159+
pq := hp{}
160+
for _, v := range timeReq {
161+
heap.Push(&pq, v)
162+
}
163+
for pq.Len() > 1 {
164+
heap.Pop(&pq)
165+
heap.Push(&pq, heap.Pop(&pq).(int)+splitTime)
166+
}
167+
return int64(pq.IntSlice[0])
168+
}
169+
170+
type hp struct{ sort.IntSlice }
171+
172+
func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
173+
func (h *hp) Pop() any {
174+
a := h.IntSlice
175+
v := a[len(a)-1]
176+
h.IntSlice = a[:len(a)-1]
177+
return v
178+
}
179+
```
180+
181+
#### TypeScript
182+
183+
```ts
184+
function minEliminationTime(timeReq: number[], splitTime: number): number {
185+
const pq = new MinPriorityQueue();
186+
for (const b of timeReq) {
187+
pq.enqueue(b);
188+
}
189+
while (pq.size() > 1) {
190+
pq.dequeue()!;
191+
pq.enqueue(pq.dequeue()! + splitTime);
192+
}
193+
return pq.dequeue()!;
194+
}
195+
```
112196

197+
#### Rust
198+
199+
```rust
200+
use std::cmp::Reverse;
201+
use std::collections::BinaryHeap;
202+
203+
impl Solution {
204+
pub fn min_elimination_time(time_req: Vec<i32>, split_time: i32) -> i64 {
205+
let mut pq = BinaryHeap::new();
206+
for x in time_req {
207+
pq.push(Reverse(x as i64));
208+
}
209+
while pq.len() > 1 {
210+
pq.pop();
211+
let merged = pq.pop().unwrap().0 + split_time as i64;
212+
pq.push(Reverse(merged));
213+
}
214+
pq.pop().unwrap().0
215+
}
216+
}
113217
```
114218

115219
<!-- tabs:end -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Solution {
2+
public:
3+
long long minEliminationTime(vector<int>& timeReq, int splitTime) {
4+
using ll = long long;
5+
priority_queue<ll, vector<ll>, greater<ll>> pq;
6+
for (int v : timeReq) {
7+
pq.push(v);
8+
}
9+
while (pq.size() > 1) {
10+
pq.pop();
11+
ll x = pq.top();
12+
pq.pop();
13+
pq.push(x + splitTime);
14+
}
15+
return pq.top();
16+
}
17+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
func minEliminationTime(timeReq []int, splitTime int) int64 {
2+
pq := hp{}
3+
for _, v := range timeReq {
4+
heap.Push(&pq, v)
5+
}
6+
for pq.Len() > 1 {
7+
heap.Pop(&pq)
8+
heap.Push(&pq, heap.Pop(&pq).(int)+splitTime)
9+
}
10+
return int64(pq.IntSlice[0])
11+
}
12+
13+
type hp struct{ sort.IntSlice }
14+
15+
func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
16+
func (h *hp) Pop() any {
17+
a := h.IntSlice
18+
v := a[len(a)-1]
19+
h.IntSlice = a[:len(a)-1]
20+
return v
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Solution {
2+
public long minEliminationTime(int[] timeReq, int splitTime) {
3+
PriorityQueue<Long> q = new PriorityQueue<>();
4+
for (int x : timeReq) {
5+
q.offer((long) x);
6+
}
7+
while (q.size() > 1) {
8+
q.poll();
9+
q.offer(q.poll() + splitTime);
10+
}
11+
return q.poll();
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Solution:
2+
def minEliminationTime(self, timeReq: List[int], splitTime: int) -> int:
3+
heapify(timeReq)
4+
while len(timeReq) > 1:
5+
heappop(timeReq)
6+
heappush(timeReq, heappop(timeReq) + splitTime)
7+
return timeReq[0]

0 commit comments

Comments
 (0)