Skip to content

Commit 4e33320

Browse files
committed
feat: add solutions to lc problem: No.3408
No.3408.Design Task Manager
1 parent 520728e commit 4e33320

File tree

4 files changed

+425
-2
lines changed

4 files changed

+425
-2
lines changed

solution/3400-3499/3408.Design Task Manager/README.md

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,21 @@ taskManager.execTop(); // 返回 5 。执行用户 5 的任务 105 。</div>
8686

8787
<!-- solution:start -->
8888

89-
### 方法一
89+
### 方法一:哈希表 + 有序集合
90+
91+
我们用一个哈希表 $\text{d}$ 来存储任务信息,键为任务 ID,值为一个二元组 $(\text{userId}, \text{priority})$,表示该任务所属的用户 ID 以及任务的优先级。
92+
93+
我们用一个有序集合 $\text{st}$ 来存储当前系统中的所有任务,元素为一个二元组 $(-\text{priority}, -\text{taskId})$,表示任务的优先级和任务 ID 的相反数。我们将优先级和任务 ID 取相反数是为了让优先级最高且任务 ID 最大的任务在有序集合中排在最前面。
94+
95+
对于每个操作,我们可以按如下方式进行处理:
96+
97+
- **初始化**:对于每个任务 $(\text{userId}, \text{taskId}, \text{priority})$,我们将其添加到哈希表 $\text{d}$ 和有序集合 $\text{st}$ 中。
98+
- **添加任务**:将任务 $(\text{userId}, \text{taskId}, \text{priority})$ 添加到哈希表 $\text{d}$ 和有序集合 $\text{st}$ 中。
99+
- **编辑任务**:从哈希表 $\text{d}$ 中获取任务 ID对应的用户 ID 和旧优先级,然后从有序集合 $\text{st}$ 中删除旧的任务信息,再将新的任务信息添加到哈希表 $\text{d}$ 和有序集合 $\text{st}$ 中。
100+
- **删除任务**:从哈希表 $\text{d}$ 中获取任务 ID 对应的优先级,然后从有序集合 $\text{st}$ 中删除任务信息,并从哈希表 $\text{d}$ 中删除任务。
101+
- **执行最高优先级任务**:如果有序集合 $\text{st}$ 为空,返回 -1。否则,从有序集合 $\text{st}$ 中取出第一个元素,获取任务 ID,然后从哈希表 $\text{d}$ 中获取对应的用户 ID,并将任务从哈希表 $\text{d}$ 和有序集合 $\text{st}$ 中删除,最后返回用户 ID。
102+
103+
时间复杂度方面,初始化操作需要 $O(n \log n)$ 的时间,其中 $n$ 是初始任务的数量。每个添加、编辑、删除和执行操作都需要 $O(\log m)$ 的时间,其中 $m$ 是当前系统中的任务数量。由于总操作次数不超过 $2 \times 10^5$,因此整体时间复杂度是可接受的。空间复杂度 $O(n + m)$,用于存储哈希表和有序集合。
90104

91105
<!-- tabs:start -->
92106

@@ -249,7 +263,140 @@ public:
249263
#### Go
250264
251265
```go
266+
type TaskManager struct {
267+
d map[int][2]int
268+
st *redblacktree.Tree[int, int]
269+
}
270+
271+
func encode(priority, taskId int) int {
272+
return (priority << 32) | taskId
273+
}
274+
275+
func comparator(a, b int) int {
276+
if a > b {
277+
return -1
278+
} else if a < b {
279+
return 1
280+
}
281+
return 0
282+
}
283+
284+
func Constructor(tasks [][]int) TaskManager {
285+
tm := TaskManager{
286+
d: make(map[int][2]int),
287+
st: redblacktree.NewWith[int, int](comparator),
288+
}
289+
for _, task := range tasks {
290+
tm.Add(task[0], task[1], task[2])
291+
}
292+
return tm
293+
}
294+
295+
func (this *TaskManager) Add(userId int, taskId int, priority int) {
296+
this.d[taskId] = [2]int{userId, priority}
297+
this.st.Put(encode(priority, taskId), taskId)
298+
}
252299
300+
func (this *TaskManager) Edit(taskId int, newPriority int) {
301+
if e, ok := this.d[taskId]; ok {
302+
priority := e[1]
303+
this.st.Remove(encode(priority, taskId))
304+
this.d[taskId] = [2]int{e[0], newPriority}
305+
this.st.Put(encode(newPriority, taskId), taskId)
306+
}
307+
}
308+
309+
func (this *TaskManager) Rmv(taskId int) {
310+
if e, ok := this.d[taskId]; ok {
311+
priority := e[1]
312+
delete(this.d, taskId)
313+
this.st.Remove(encode(priority, taskId))
314+
}
315+
}
316+
317+
func (this *TaskManager) ExecTop() int {
318+
if this.st.Empty() {
319+
return -1
320+
}
321+
it := this.st.Iterator()
322+
it.Next()
323+
taskId := it.Value()
324+
if e, ok := this.d[taskId]; ok {
325+
delete(this.d, taskId)
326+
this.st.Remove(it.Key())
327+
return e[0]
328+
}
329+
return -1
330+
}
331+
332+
/**
333+
* Your TaskManager object will be instantiated and called as such:
334+
* obj := Constructor(tasks);
335+
* obj.Add(userId,taskId,priority);
336+
* obj.Edit(taskId,newPriority);
337+
* obj.Rmv(taskId);
338+
* param_4 := obj.ExecTop();
339+
*/
340+
```
341+
342+
#### TypeScript
343+
344+
```ts
345+
class TaskManager {
346+
private d: Map<number, [number, number]>;
347+
private pq: PriorityQueue<[number, number]>;
348+
349+
constructor(tasks: number[][]) {
350+
this.d = new Map();
351+
this.pq = new PriorityQueue<[number, number]>((a, b) => {
352+
if (a[0] === b[0]) {
353+
return b[1] - a[1];
354+
}
355+
return b[0] - a[0];
356+
});
357+
for (const task of tasks) {
358+
this.add(task[0], task[1], task[2]);
359+
}
360+
}
361+
362+
add(userId: number, taskId: number, priority: number): void {
363+
this.d.set(taskId, [userId, priority]);
364+
this.pq.enqueue([priority, taskId]);
365+
}
366+
367+
edit(taskId: number, newPriority: number): void {
368+
const e = this.d.get(taskId);
369+
if (!e) return;
370+
const userId = e[0];
371+
this.d.set(taskId, [userId, newPriority]);
372+
this.pq.enqueue([newPriority, taskId]);
373+
}
374+
375+
rmv(taskId: number): void {
376+
this.d.delete(taskId);
377+
}
378+
379+
execTop(): number {
380+
while (!this.pq.isEmpty()) {
381+
const [priority, taskId] = this.pq.dequeue();
382+
const e = this.d.get(taskId);
383+
if (e && e[1] === priority) {
384+
this.d.delete(taskId);
385+
return e[0];
386+
}
387+
}
388+
return -1;
389+
}
390+
}
391+
392+
/**
393+
* Your TaskManager object will be instantiated and called as such:
394+
* var obj = new TaskManager(tasks)
395+
* obj.add(userId,taskId,priority)
396+
* obj.edit(taskId,newPriority)
397+
* obj.rmv(taskId)
398+
* var param_4 = obj.execTop()
399+
*/
253400
```
254401

255402
<!-- tabs:end -->

solution/3400-3499/3408.Design Task Manager/README_EN.md

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,21 @@ taskManager.execTop(); // return 5. Executes task 105 for User 5.</div>
8484

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

87-
### Solution 1
87+
### Solution 1: Hash Map + Ordered Set
88+
89+
We use a hash map $\text{d}$ to store task information, where the key is the task ID and the value is a tuple $(\text{userId}, \text{priority})$ representing the user ID and the priority of the task.
90+
91+
We use an ordered set $\text{st}$ to store all tasks currently in the system, where each element is a tuple $(-\text{priority}, -\text{taskId})$ representing the negative priority and negative task ID. We use negative values so that the task with the highest priority and largest task ID appears first in the ordered set.
92+
93+
For each operation, we can process as follows:
94+
95+
- **Initialization**: For each task $(\text{userId}, \text{taskId}, \text{priority})$, add it to the hash map $\text{d}$ and the ordered set $\text{st}$.
96+
- **Add Task**: Add the task $(\text{userId}, \text{taskId}, \text{priority})$ to the hash map $\text{d}$ and the ordered set $\text{st}$.
97+
- **Edit Task**: Retrieve the user ID and old priority for the given task ID from the hash map $\text{d}$, remove the old task information from the ordered set $\text{st}$, then add the new task information to both the hash map and the ordered set.
98+
- **Remove Task**: Retrieve the priority for the given task ID from the hash map $\text{d}$, remove the task information from the ordered set $\text{st}$, and delete the task from the hash map.
99+
- **Execute Top Priority Task**: If the ordered set $\text{st}$ is empty, return -1. Otherwise, take the first element from the ordered set, get the task ID, retrieve the corresponding user ID from the hash map, and remove the task from both the hash map and the ordered set. Finally, return the user ID.
100+
101+
For time complexity, initialization requires $O(n \log n)$ time, where $n$ is the number of initial tasks. Each add, edit, remove, and execute operation requires $O(\log m)$ time, where $m$ is the current number of tasks in the system. Since the total number of operations does not exceed $2 \times 10^5$, the overall time complexity is acceptable. The space complexity is $O(n + m)$ for storing the hash map and ordered set.
88102

89103
<!-- tabs:start -->
90104

@@ -247,7 +261,140 @@ public:
247261
#### Go
248262
249263
```go
264+
type TaskManager struct {
265+
d map[int][2]int
266+
st *redblacktree.Tree[int, int]
267+
}
268+
269+
func encode(priority, taskId int) int {
270+
return (priority << 32) | taskId
271+
}
272+
273+
func comparator(a, b int) int {
274+
if a > b {
275+
return -1
276+
} else if a < b {
277+
return 1
278+
}
279+
return 0
280+
}
281+
282+
func Constructor(tasks [][]int) TaskManager {
283+
tm := TaskManager{
284+
d: make(map[int][2]int),
285+
st: redblacktree.NewWith[int, int](comparator),
286+
}
287+
for _, task := range tasks {
288+
tm.Add(task[0], task[1], task[2])
289+
}
290+
return tm
291+
}
292+
293+
func (this *TaskManager) Add(userId int, taskId int, priority int) {
294+
this.d[taskId] = [2]int{userId, priority}
295+
this.st.Put(encode(priority, taskId), taskId)
296+
}
250297
298+
func (this *TaskManager) Edit(taskId int, newPriority int) {
299+
if e, ok := this.d[taskId]; ok {
300+
priority := e[1]
301+
this.st.Remove(encode(priority, taskId))
302+
this.d[taskId] = [2]int{e[0], newPriority}
303+
this.st.Put(encode(newPriority, taskId), taskId)
304+
}
305+
}
306+
307+
func (this *TaskManager) Rmv(taskId int) {
308+
if e, ok := this.d[taskId]; ok {
309+
priority := e[1]
310+
delete(this.d, taskId)
311+
this.st.Remove(encode(priority, taskId))
312+
}
313+
}
314+
315+
func (this *TaskManager) ExecTop() int {
316+
if this.st.Empty() {
317+
return -1
318+
}
319+
it := this.st.Iterator()
320+
it.Next()
321+
taskId := it.Value()
322+
if e, ok := this.d[taskId]; ok {
323+
delete(this.d, taskId)
324+
this.st.Remove(it.Key())
325+
return e[0]
326+
}
327+
return -1
328+
}
329+
330+
/**
331+
* Your TaskManager object will be instantiated and called as such:
332+
* obj := Constructor(tasks);
333+
* obj.Add(userId,taskId,priority);
334+
* obj.Edit(taskId,newPriority);
335+
* obj.Rmv(taskId);
336+
* param_4 := obj.ExecTop();
337+
*/
338+
```
339+
340+
#### TypeScript
341+
342+
```ts
343+
class TaskManager {
344+
private d: Map<number, [number, number]>;
345+
private pq: PriorityQueue<[number, number]>;
346+
347+
constructor(tasks: number[][]) {
348+
this.d = new Map();
349+
this.pq = new PriorityQueue<[number, number]>((a, b) => {
350+
if (a[0] === b[0]) {
351+
return b[1] - a[1];
352+
}
353+
return b[0] - a[0];
354+
});
355+
for (const task of tasks) {
356+
this.add(task[0], task[1], task[2]);
357+
}
358+
}
359+
360+
add(userId: number, taskId: number, priority: number): void {
361+
this.d.set(taskId, [userId, priority]);
362+
this.pq.enqueue([priority, taskId]);
363+
}
364+
365+
edit(taskId: number, newPriority: number): void {
366+
const e = this.d.get(taskId);
367+
if (!e) return;
368+
const userId = e[0];
369+
this.d.set(taskId, [userId, newPriority]);
370+
this.pq.enqueue([newPriority, taskId]);
371+
}
372+
373+
rmv(taskId: number): void {
374+
this.d.delete(taskId);
375+
}
376+
377+
execTop(): number {
378+
while (!this.pq.isEmpty()) {
379+
const [priority, taskId] = this.pq.dequeue();
380+
const e = this.d.get(taskId);
381+
if (e && e[1] === priority) {
382+
this.d.delete(taskId);
383+
return e[0];
384+
}
385+
}
386+
return -1;
387+
}
388+
}
389+
390+
/**
391+
* Your TaskManager object will be instantiated and called as such:
392+
* var obj = new TaskManager(tasks)
393+
* obj.add(userId,taskId,priority)
394+
* obj.edit(taskId,newPriority)
395+
* obj.rmv(taskId)
396+
* var param_4 = obj.execTop()
397+
*/
251398
```
252399

253400
<!-- tabs:end -->

0 commit comments

Comments
 (0)