There is a task management system that allows users to manage their tasks, each associated with a priority. The system should efficiently handle adding, modifying, executing, and removing tasks.
Implement the TaskManager class:
TaskManager(vector<vector<int>>& tasks) initializes the task manager with a list of user-task-priority triples. Each element in the input list is of the form [userId, taskId, priority], which adds a task to the specified user with the given priority.
void add(int userId, int taskId, int priority) adds a task with the specified taskId and priority to the user with userId. It is guaranteed that taskId does not exist in the system.
void edit(int taskId, int newPriority) updates the priority of the existing taskId to newPriority. It is guaranteed that taskIdexists in the system.
void rmv(int taskId) removes the task identified by taskId from the system. It is guaranteed that taskIdexists in the system.
int execTop() executes the task with the highest priority across all users. If there are multiple tasks with the same highest priority, execute the one with the highest taskId. After executing, thetaskIdis removed from the system. Return the userId associated with the executed task. If no tasks are available, return -1.
TaskManager taskManager = new TaskManager([[1, 101, 10], [2, 102, 20], [3, 103, 15]]); // Initializes with three tasks for Users 1, 2, and 3.
taskManager.add(4, 104, 5); // Adds task 104 with priority 5 for User 4.
taskManager.edit(102, 8); // Updates priority of task 102 to 8.
taskManager.execTop(); // return 3. Executes task 103 for User 3.
taskManager.rmv(101); // Removes task 101 from the system.
taskManager.add(5, 105, 15); // Adds task 105 with priority 15 for User 5.
taskManager.execTop(); // return 5. Executes task 105 for User 5.
Constraints:
1 <= tasks.length <= 105
0 <= userId <= 105
0 <= taskId <= 105
0 <= priority <= 109
0 <= newPriority <= 109
At most 2 * 105 calls will be made in total to add, edit, rmv, and execTop methods.
The input is generated such that taskId will be valid.
Solutions
Solution 1: Hash Map + Ordered Set
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.
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.
For each operation, we can process as follows:
Initialization: For each task \((\text{userId}, \text{taskId}, \text{priority})\), add it to the hash map \(\text{d}\) and the ordered set \(\text{st}\).
Add Task: Add the task \((\text{userId}, \text{taskId}, \text{priority})\) to the hash map \(\text{d}\) and the ordered set \(\text{st}\).
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.
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.
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.
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.
classTaskManager:def__init__(self,tasks:List[List[int]]):self.d={}self.st=SortedList()fortaskintasks:self.add(*task)defadd(self,userId:int,taskId:int,priority:int)->None:self.d[taskId]=(userId,priority)self.st.add((-priority,-taskId))defedit(self,taskId:int,newPriority:int)->None:userId,priority=self.d[taskId]self.st.discard((-priority,-taskId))self.d[taskId]=(userId,newPriority)self.st.add((-newPriority,-taskId))defrmv(self,taskId:int)->None:_,priority=self.d[taskId]self.d.pop(taskId)self.st.remove((-priority,-taskId))defexecTop(self)->int:ifnotself.st:return-1taskId=-self.st.pop(0)[1]userId,_=self.d[taskId]self.d.pop(taskId)returnuserId# Your TaskManager object will be instantiated and called as such:# obj = TaskManager(tasks)# obj.add(userId,taskId,priority)# obj.edit(taskId,newPriority)# obj.rmv(taskId)# param_4 = obj.execTop()
classTaskManager{privatefinalMap<Integer,int[]>d=newHashMap<>();privatefinalTreeSet<int[]>st=newTreeSet<>((a,b)->{if(a[0]==b[0]){returnb[1]-a[1];}returnb[0]-a[0];});publicTaskManager(List<List<Integer>>tasks){for(vartask:tasks){add(task.get(0),task.get(1),task.get(2));}}publicvoidadd(intuserId,inttaskId,intpriority){d.put(taskId,newint[]{userId,priority});st.add(newint[]{priority,taskId});}publicvoidedit(inttaskId,intnewPriority){vare=d.get(taskId);intuserId=e[0],priority=e[1];st.remove(newint[]{priority,taskId});st.add(newint[]{newPriority,taskId});d.put(taskId,newint[]{userId,newPriority});}publicvoidrmv(inttaskId){vare=d.remove(taskId);intpriority=e[1];st.remove(newint[]{priority,taskId});}publicintexecTop(){if(st.isEmpty()){return-1;}vare=st.pollFirst();vart=d.remove(e[1]);returnt[0];}}/** * Your TaskManager object will be instantiated and called as such: * TaskManager obj = new TaskManager(tasks); * obj.add(userId,taskId,priority); * obj.edit(taskId,newPriority); * obj.rmv(taskId); * int param_4 = obj.execTop(); */
classTaskManager{private:unordered_map<int,pair<int,int>>d;set<pair<int,int>>st;public:TaskManager(vector<vector<int>>&tasks){for(constauto&task:tasks){add(task[0],task[1],task[2]);}}voidadd(intuserId,inttaskId,intpriority){d[taskId]={userId,priority};st.insert({-priority,-taskId});}voidedit(inttaskId,intnewPriority){auto[userId,priority]=d[taskId];st.erase({-priority,-taskId});st.insert({-newPriority,-taskId});d[taskId]={userId,newPriority};}voidrmv(inttaskId){auto[userId,priority]=d[taskId];st.erase({-priority,-taskId});d.erase(taskId);}intexecTop(){if(st.empty()){return-1;}autoe=*st.begin();st.erase(st.begin());inttaskId=-e.second;intuserId=d[taskId].first;d.erase(taskId);returnuserId;}};/** * Your TaskManager object will be instantiated and called as such: * TaskManager* obj = new TaskManager(tasks); * obj->add(userId,taskId,priority); * obj->edit(taskId,newPriority); * obj->rmv(taskId); * int param_4 = obj->execTop(); */
typeTaskManagerstruct{dmap[int][2]intst*redblacktree.Tree[int,int]}funcencode(priority,taskIdint)int{return(priority<<32)|taskId}funccomparator(a,bint)int{ifa>b{return-1}elseifa<b{return1}return0}funcConstructor(tasks[][]int)TaskManager{tm:=TaskManager{d:make(map[int][2]int),st:redblacktree.NewWith[int,int](comparator),}for_,task:=rangetasks{tm.Add(task[0],task[1],task[2])}returntm}func(this*TaskManager)Add(userIdint,taskIdint,priorityint){this.d[taskId]=[2]int{userId,priority}this.st.Put(encode(priority,taskId),taskId)}func(this*TaskManager)Edit(taskIdint,newPriorityint){ife,ok:=this.d[taskId];ok{priority:=e[1]this.st.Remove(encode(priority,taskId))this.d[taskId]=[2]int{e[0],newPriority}this.st.Put(encode(newPriority,taskId),taskId)}}func(this*TaskManager)Rmv(taskIdint){ife,ok:=this.d[taskId];ok{priority:=e[1]delete(this.d,taskId)this.st.Remove(encode(priority,taskId))}}func(this*TaskManager)ExecTop()int{ifthis.st.Empty(){return-1}it:=this.st.Iterator()it.Next()taskId:=it.Value()ife,ok:=this.d[taskId];ok{delete(this.d,taskId)this.st.Remove(it.Key())returne[0]}return-1}/** * Your TaskManager object will be instantiated and called as such: * obj := Constructor(tasks); * obj.Add(userId,taskId,priority); * obj.Edit(taskId,newPriority); * obj.Rmv(taskId); * param_4 := obj.ExecTop(); */
classTaskManager{privated:Map<number,[number,number]>;privatepq:PriorityQueue<[number,number]>;constructor(tasks:number[][]){this.d=newMap();this.pq=newPriorityQueue<[number,number]>((a,b)=>{if(a[0]===b[0]){returnb[1]-a[1];}returnb[0]-a[0];});for(consttaskoftasks){this.add(task[0],task[1],task[2]);}}add(userId:number,taskId:number,priority:number):void{this.d.set(taskId,[userId,priority]);this.pq.enqueue([priority,taskId]);}edit(taskId:number,newPriority:number):void{conste=this.d.get(taskId);if(!e)return;constuserId=e[0];this.d.set(taskId,[userId,newPriority]);this.pq.enqueue([newPriority,taskId]);}rmv(taskId:number):void{this.d.delete(taskId);}execTop():number{while(!this.pq.isEmpty()){const[priority,taskId]=this.pq.dequeue();conste=this.d.get(taskId);if(e&&e[1]===priority){this.d.delete(taskId);returne[0];}}return-1;}}/** * Your TaskManager object will be instantiated and called as such: * var obj = new TaskManager(tasks) * obj.add(userId,taskId,priority) * obj.edit(taskId,newPriority) * obj.rmv(taskId) * var param_4 = obj.execTop() */