Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add solutions to lc problem: No.3506 #4318

Merged
merged 1 commit into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions solution/1100-1199/1199.Minimum Time to Build Blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ tags:

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

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

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

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

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

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

Expand Down Expand Up @@ -176,9 +176,9 @@ function minBuildTime(blocks: number[], split: number): number {
}
while (pq.size() > 1) {
pq.dequeue()!;
pq.enqueue(pq.dequeue()!.element + split);
pq.enqueue(pq.dequeue()! + split);
}
return pq.dequeue()!.element;
return pq.dequeue()!;
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ function minBuildTime(blocks: number[], split: number): number {
}
while (pq.size() > 1) {
pq.dequeue()!;
pq.enqueue(pq.dequeue()!.element + split);
pq.enqueue(pq.dequeue()! + split);
}
return pq.dequeue()!.element;
return pq.dequeue()!;
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function minBuildTime(blocks: number[], split: number): number {
}
while (pq.size() > 1) {
pq.dequeue()!;
pq.enqueue(pq.dequeue()!.element + split);
pq.enqueue(pq.dequeue()! + split);
}
return pq.dequeue()!.element;
return pq.dequeue()!;
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,32 +84,136 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3500-3599/3506.Fi

<!-- solution:start -->

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

先考虑只有一种细菌的情况,此时不需要分裂白细胞,直接让他去消灭细菌,时间花费为 $\textit{timeSeq}[0]$。

如果有两种细菌,此时需要把白细胞分裂为两种,然后让它们分别去消灭细菌,时间花费为 $\textit{splitTime} + \max(\textit{timeSeq}[0], \textit{timeSeq}[1])$。

如果有超过两种细菌,此时每一步都需要考虑将几个白细胞进行分裂,正向思维不好处理。

我们不妨采用逆向思维,不分裂白细胞,而是将细菌进行合并。我们选取任意两种细菌 $i$, $j$ 进行合并,合并成一种新的细菌的时间为 $\textit{splitTime} + \max(\textit{timeSeq}[i], \textit{timeSeq}[j])$。

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

时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为细菌的数量。

<!-- tabs:start -->

#### Python3

```python

class Solution:
def minEliminationTime(self, timeReq: List[int], splitTime: int) -> int:
heapify(timeReq)
while len(timeReq) > 1:
heappop(timeReq)
heappush(timeReq, heappop(timeReq) + splitTime)
return timeReq[0]
```

#### Java

```java

class Solution {
public long minEliminationTime(int[] timeReq, int splitTime) {
PriorityQueue<Long> q = new PriorityQueue<>();
for (int x : timeReq) {
q.offer((long) x);
}
while (q.size() > 1) {
q.poll();
q.offer(q.poll() + splitTime);
}
return q.poll();
}
}
```

#### C++

```cpp

class Solution {
public:
long long minEliminationTime(vector<int>& timeReq, int splitTime) {
using ll = long long;
priority_queue<ll, vector<ll>, greater<ll>> pq;
for (int v : timeReq) {
pq.push(v);
}
while (pq.size() > 1) {
pq.pop();
ll x = pq.top();
pq.pop();
pq.push(x + splitTime);
}
return pq.top();
}
};
```

#### Go

```go
func minEliminationTime(timeReq []int, splitTime int) int64 {
pq := hp{}
for _, v := range timeReq {
heap.Push(&pq, v)
}
for pq.Len() > 1 {
heap.Pop(&pq)
heap.Push(&pq, heap.Pop(&pq).(int)+splitTime)
}
return int64(pq.IntSlice[0])
}

type hp struct{ sort.IntSlice }

func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() any {
a := h.IntSlice
v := a[len(a)-1]
h.IntSlice = a[:len(a)-1]
return v
}
```

#### TypeScript

```ts
function minEliminationTime(timeReq: number[], splitTime: number): number {
const pq = new MinPriorityQueue();
for (const b of timeReq) {
pq.enqueue(b);
}
while (pq.size() > 1) {
pq.dequeue()!;
pq.enqueue(pq.dequeue()! + splitTime);
}
return pq.dequeue()!;
}
```

#### Rust

```rust
use std::cmp::Reverse;
use std::collections::BinaryHeap;

impl Solution {
pub fn min_elimination_time(time_req: Vec<i32>, split_time: i32) -> i64 {
let mut pq = BinaryHeap::new();
for x in time_req {
pq.push(Reverse(x as i64));
}
while pq.len() > 1 {
pq.pop();
let merged = pq.pop().unwrap().0 + split_time as i64;
pq.push(Reverse(merged));
}
pq.pop().unwrap().0
}
}
```

<!-- tabs:end -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,32 +84,136 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3500-3599/3506.Fi

<!-- solution:start -->

### Solution 1
### Solution 1: Greedy + Priority Queue (Min-Heap)

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]$.

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])$.

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.

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])$.

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.

The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$, where $n$ is the number of bacteria.

<!-- tabs:start -->

#### Python3

```python

class Solution:
def minEliminationTime(self, timeReq: List[int], splitTime: int) -> int:
heapify(timeReq)
while len(timeReq) > 1:
heappop(timeReq)
heappush(timeReq, heappop(timeReq) + splitTime)
return timeReq[0]
```

#### Java

```java

class Solution {
public long minEliminationTime(int[] timeReq, int splitTime) {
PriorityQueue<Long> q = new PriorityQueue<>();
for (int x : timeReq) {
q.offer((long) x);
}
while (q.size() > 1) {
q.poll();
q.offer(q.poll() + splitTime);
}
return q.poll();
}
}
```

#### C++

```cpp

class Solution {
public:
long long minEliminationTime(vector<int>& timeReq, int splitTime) {
using ll = long long;
priority_queue<ll, vector<ll>, greater<ll>> pq;
for (int v : timeReq) {
pq.push(v);
}
while (pq.size() > 1) {
pq.pop();
ll x = pq.top();
pq.pop();
pq.push(x + splitTime);
}
return pq.top();
}
};
```

#### Go

```go
func minEliminationTime(timeReq []int, splitTime int) int64 {
pq := hp{}
for _, v := range timeReq {
heap.Push(&pq, v)
}
for pq.Len() > 1 {
heap.Pop(&pq)
heap.Push(&pq, heap.Pop(&pq).(int)+splitTime)
}
return int64(pq.IntSlice[0])
}

type hp struct{ sort.IntSlice }

func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() any {
a := h.IntSlice
v := a[len(a)-1]
h.IntSlice = a[:len(a)-1]
return v
}
```

#### TypeScript

```ts
function minEliminationTime(timeReq: number[], splitTime: number): number {
const pq = new MinPriorityQueue();
for (const b of timeReq) {
pq.enqueue(b);
}
while (pq.size() > 1) {
pq.dequeue()!;
pq.enqueue(pq.dequeue()! + splitTime);
}
return pq.dequeue()!;
}
```

#### Rust

```rust
use std::cmp::Reverse;
use std::collections::BinaryHeap;

impl Solution {
pub fn min_elimination_time(time_req: Vec<i32>, split_time: i32) -> i64 {
let mut pq = BinaryHeap::new();
for x in time_req {
pq.push(Reverse(x as i64));
}
while pq.len() > 1 {
pq.pop();
let merged = pq.pop().unwrap().0 + split_time as i64;
pq.push(Reverse(merged));
}
pq.pop().unwrap().0
}
}
```

<!-- tabs:end -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Solution {
public:
long long minEliminationTime(vector<int>& timeReq, int splitTime) {
using ll = long long;
priority_queue<ll, vector<ll>, greater<ll>> pq;
for (int v : timeReq) {
pq.push(v);
}
while (pq.size() > 1) {
pq.pop();
ll x = pq.top();
pq.pop();
pq.push(x + splitTime);
}
return pq.top();
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
func minEliminationTime(timeReq []int, splitTime int) int64 {
pq := hp{}
for _, v := range timeReq {
heap.Push(&pq, v)
}
for pq.Len() > 1 {
heap.Pop(&pq)
heap.Push(&pq, heap.Pop(&pq).(int)+splitTime)
}
return int64(pq.IntSlice[0])
}

type hp struct{ sort.IntSlice }

func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() any {
a := h.IntSlice
v := a[len(a)-1]
h.IntSlice = a[:len(a)-1]
return v
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Solution {
public long minEliminationTime(int[] timeReq, int splitTime) {
PriorityQueue<Long> q = new PriorityQueue<>();
for (int x : timeReq) {
q.offer((long) x);
}
while (q.size() > 1) {
q.poll();
q.offer(q.poll() + splitTime);
}
return q.poll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Solution:
def minEliminationTime(self, timeReq: List[int], splitTime: int) -> int:
heapify(timeReq)
while len(timeReq) > 1:
heappop(timeReq)
heappush(timeReq, heappop(timeReq) + splitTime)
return timeReq[0]
Loading