Skip to content

Commit a31e3f7

Browse files
chore: add LeetCode daily solution
1 parent 77158a6 commit a31e3f7

File tree

5 files changed

+240
-0
lines changed

5 files changed

+240
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Design Task Manager (Medium)
2+
3+
**Problem ID:** 3408
4+
**Date:** 2025-09-18
5+
**Link:** https://leetcode.com/problems/design-task-manager/
6+
7+
## Approach
8+
9+
To solve the "Design Task Manager" problem, we need to efficiently manage tasks associated with users, each having a priority. The core operations we need to support are adding, editing, removing, and executing tasks based on their priority and task ID.
10+
11+
### Main Idea:
12+
The main idea is to utilize a priority queue (or max-heap) to keep track of tasks based on their priorities. This allows us to efficiently retrieve and execute the task with the highest priority. If multiple tasks share the same priority, we will use the task ID to break ties, ensuring that the task with the higher ID is executed first.
13+
14+
### Data Structures:
15+
1. **Priority Queue (Max-Heap)**: This will store tasks in the format `(priority, taskId, userId)`. The priority queue will allow us to efficiently access and remove the task with the highest priority.
16+
2. **Hash Map (Dictionary)**: This will map `taskId` to a tuple `(priority, userId)` for quick access to task details when editing or removing tasks. This ensures that we can efficiently update the priority or remove a task without needing to search through the priority queue.
17+
18+
### Operations:
19+
1. **Initialization**: Populate the priority queue and hash map with the initial list of tasks.
20+
2. **Add Task**: Insert the new task into the priority queue and hash map.
21+
3. **Edit Task**: Update the task's priority in the hash map, and reinsert it into the priority queue to maintain the correct order.
22+
4. **Remove Task**: Remove the task from the hash map. To ensure consistency in the priority queue, we can mark the task as removed and handle its removal lazily during the `execTop` operation.
23+
5. **Execute Top Task**: Continuously extract the top task from the priority queue until we find a task that is still valid (not marked for removal). Return the `userId` of the executed task and remove it from the hash map.
24+
25+
### Complexity:
26+
- **Time Complexity**:
27+
- Adding a task: O(log n) for insertion into the priority queue.
28+
- Editing a task: O(log n) for reinserting into the priority queue after updating the hash map.
29+
- Removing a task: O(1) for updating the hash map, but O(log n) for cleaning up the priority queue during execution.
30+
- Executing the top task: O(log n) for each extraction from the priority queue, but may involve multiple extractions in the worst case if many tasks are marked as removed.
31+
32+
- **Space Complexity**: O(n) for storing tasks in both the priority queue and hash map.
33+
34+
This approach ensures that all operations are efficient and can handle the constraints provided in the problem statement. By leveraging a combination of a priority queue and a hash map, we achieve both fast access and priority management for the tasks.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import java.util.*;
2+
3+
class TaskManager {
4+
private final Map<Integer, Task> taskMap;
5+
private final PriorityQueue<Task> taskQueue;
6+
7+
public TaskManager(int[][] tasks) {
8+
taskMap = new HashMap<>();
9+
taskQueue = new PriorityQueue<>((a, b) -> {
10+
if (b.priority != a.priority) {
11+
return Integer.compare(b.priority, a.priority);
12+
}
13+
return Integer.compare(b.taskId, a.taskId);
14+
});
15+
for (int[] task : tasks) {
16+
add(task[0], task[1], task[2]);
17+
}
18+
}
19+
20+
public void add(int userId, int taskId, int priority) {
21+
Task newTask = new Task(userId, taskId, priority);
22+
taskMap.put(taskId, newTask);
23+
taskQueue.offer(newTask);
24+
}
25+
26+
public void edit(int taskId, int newPriority) {
27+
Task task = taskMap.get(taskId);
28+
if (task != null) {
29+
taskQueue.remove(task);
30+
task.priority = newPriority;
31+
taskQueue.offer(task);
32+
}
33+
}
34+
35+
public void rmv(int taskId) {
36+
Task task = taskMap.remove(taskId);
37+
if (task != null) {
38+
taskQueue.remove(task);
39+
}
40+
}
41+
42+
public int execTop() {
43+
while (!taskQueue.isEmpty()) {
44+
Task topTask = taskQueue.poll();
45+
if (topTask != null && taskMap.containsKey(topTask.taskId)) {
46+
taskMap.remove(topTask.taskId);
47+
return topTask.userId;
48+
}
49+
}
50+
return -1;
51+
}
52+
53+
private static class Task {
54+
int userId;
55+
int taskId;
56+
int priority;
57+
58+
Task(int userId, int taskId, int priority) {
59+
this.userId = userId;
60+
this.taskId = taskId;
61+
this.priority = priority;
62+
}
63+
}
64+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
class TaskManager {
2+
constructor(tasks) {
3+
this.tasks = new Map();
4+
this.maxHeap = new MaxHeap();
5+
for (const [userId, taskId, priority] of tasks) {
6+
this.tasks.set(taskId, { userId, priority });
7+
this.maxHeap.insert({ userId, taskId, priority });
8+
}
9+
}
10+
11+
add(userId, taskId, priority) {
12+
this.tasks.set(taskId, { userId, priority });
13+
this.maxHeap.insert({ userId, taskId, priority });
14+
}
15+
16+
edit(taskId, newPriority) {
17+
const task = this.tasks.get(taskId);
18+
if (task) {
19+
this.tasks.set(taskId, { ...task, priority: newPriority });
20+
this.maxHeap.insert({ userId: task.userId, taskId, priority: newPriority });
21+
}
22+
}
23+
24+
rmv(taskId) {
25+
this.tasks.delete(taskId);
26+
}
27+
28+
execTop() {
29+
while (this.maxHeap.size() > 0) {
30+
const { userId, taskId, priority } = this.maxHeap.extractMax();
31+
if (this.tasks.has(taskId) && this.tasks.get(taskId).priority === priority) {
32+
this.tasks.delete(taskId);
33+
return userId;
34+
}
35+
}
36+
return -1;
37+
}
38+
}
39+
40+
class MaxHeap {
41+
constructor() {
42+
this.heap = [];
43+
}
44+
45+
insert(value) {
46+
this.heap.push(value);
47+
this.bubbleUp();
48+
}
49+
50+
extractMax() {
51+
if (this.heap.length === 0) return null;
52+
const max = this.heap[0];
53+
const end = this.heap.pop();
54+
if (this.heap.length > 0) {
55+
this.heap[0] = end;
56+
this.bubbleDown();
57+
}
58+
return max;
59+
}
60+
61+
size() {
62+
return this.heap.length;
63+
}
64+
65+
bubbleUp() {
66+
let index = this.heap.length - 1;
67+
const element = this.heap[index];
68+
while (index > 0) {
69+
const parentIndex = Math.floor((index - 1) / 2);
70+
const parent = this.heap[parentIndex];
71+
if (element.priority > parent.priority || (element.priority === parent.priority && element.taskId > parent.taskId)) {
72+
this.heap[index] = parent;
73+
index = parentIndex;
74+
} else {
75+
break;
76+
}
77+
}
78+
this.heap[index] = element;
79+
}
80+
81+
bubbleDown() {
82+
let index = 0;
83+
const length = this.heap.length;
84+
const element = this.heap[0];
85+
while (true) {
86+
const leftChildIndex = 2 * index + 1;
87+
const rightChildIndex = 2 * index + 2;
88+
let leftChild, rightChild;
89+
let swap = null;
90+
91+
if (leftChildIndex < length) {
92+
leftChild = this.heap[leftChildIndex];
93+
if (leftChild.priority > element.priority || (leftChild.priority === element.priority && leftChild.taskId > element.taskId)) {
94+
swap = leftChildIndex;
95+
}
96+
}
97+
98+
if (rightChildIndex < length) {
99+
rightChild = this.heap[rightChildIndex];
100+
if ((swap === null && (rightChild.priority > element.priority || (rightChild.priority === element.priority && rightChild.taskId > element.taskId))) ||
101+
(swap !== null && (rightChild.priority > leftChild.priority || (rightChild.priority === leftChild.priority && rightChild.taskId > leftChild.taskId)))) {
102+
swap = rightChildIndex;
103+
}
104+
}
105+
106+
if (swap === null) break;
107+
this.heap[index] = this.heap[swap];
108+
index = swap;
109+
}
110+
this.heap[index] = element;
111+
}
112+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import heapq
2+
3+
class TaskManager:
4+
def __init__(self, tasks):
5+
self.tasks = {}
6+
self.heap = []
7+
for userId, taskId, priority in tasks:
8+
self.tasks[taskId] = (userId, priority)
9+
heapq.heappush(self.heap, (-priority, -taskId, taskId))
10+
11+
def add(self, userId: int, taskId: int, priority: int) -> None:
12+
self.tasks[taskId] = (userId, priority)
13+
heapq.heappush(self.heap, (-priority, -taskId, taskId))
14+
15+
def edit(self, taskId: int, newPriority: int) -> None:
16+
userId, _ = self.tasks[taskId]
17+
self.tasks[taskId] = (userId, newPriority)
18+
heapq.heappush(self.heap, (-newPriority, -taskId, taskId))
19+
20+
def rmv(self, taskId: int) -> None:
21+
del self.tasks[taskId]
22+
23+
def execTop(self) -> int:
24+
while self.heap:
25+
priority, negTaskId, taskId = heapq.heappop(self.heap)
26+
if taskId in self.tasks and self.tasks[taskId][1] == -priority:
27+
del self.tasks[taskId]
28+
return self.tasks[taskId][0]
29+
return -1

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,4 @@ Each problem includes:
150150
- 2025-09-14 — [Vowel Spellchecker](https://leetcode.com/problems/vowel-spellchecker/) (Medium) → `Medium/2025-09-14-966-Vowel-Spellchecker`
151151
- 2025-09-15 — [Maximum Number of Words You Can Type](https://leetcode.com/problems/maximum-number-of-words-you-can-type/) (Easy) → `Easy/2025-09-15-1935-Maximum-Number-of-Words-You-Can-Type`
152152
- 2025-09-17 — [Design a Food Rating System](https://leetcode.com/problems/design-a-food-rating-system/) (Medium) → `Medium/2025-09-17-2353-Design-a-Food-Rating-System`
153+
- 2025-09-18 — [Design Task Manager](https://leetcode.com/problems/design-task-manager/) (Medium) → `Medium/2025-09-18-3408-Design-Task-Manager`

0 commit comments

Comments
 (0)