Facebook Pixel

3408. Design Task Manager

MediumDesignHash TableOrdered SetHeap (Priority Queue)
Leetcode Link

Problem Description

This problem asks you to implement a task management system that can handle multiple users and their tasks. Each task has a priority level, and the system needs to support several operations.

The TaskManager class needs to support the following operations:

  1. Initialization: Create the task manager with an initial list of tasks. Each task is represented as [userId, taskId, priority].

  2. Add a task: Add a new task to a specific user with add(userId, taskId, priority). The taskId is guaranteed to be unique (not already in the system).

  3. Edit a task: Change the priority of an existing task with edit(taskId, newPriority). The taskId is guaranteed to exist in the system.

  4. Remove a task: Delete a task from the system with rmv(taskId). The taskId is guaranteed to exist.

  5. Execute top priority task: Execute and remove the highest priority task across all users with execTop(). If multiple tasks have the same highest priority, choose the one with the highest taskId. Return the userId of the executed task, or -1 if no tasks exist.

The solution uses two data structures:

  • A dictionary d that maps each taskId to a tuple of (userId, priority)
  • A SortedList that maintains tasks sorted by priority and taskId

The key insight is storing tasks as (-priority, -taskId) in the sorted list. This ensures that:

  • Higher priorities come first (since we negate the priority)
  • Among tasks with the same priority, higher taskIds come first (since we negate the taskId)

When executing the top task, the system simply pops the first element from the sorted list, retrieves the corresponding user information from the dictionary, and returns the userId.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The core challenge is maintaining tasks in a way that allows us to quickly find and execute the highest priority task while also supporting efficient updates and deletions.

Let's think about what data we need to track:

  • For each task, we need to know which user owns it and its priority
  • We need to find the highest priority task quickly
  • When priorities are tied, we need the highest taskId

A natural first thought might be to use a heap or priority queue. However, standard heaps don't support efficient arbitrary deletions or updates - we'd need to search through the entire heap to find a specific taskId for editing or removal.

This leads us to consider maintaining two separate data structures:

  1. A mapping to quickly look up task information by taskId
  2. A sorted structure to maintain priority ordering

For the mapping, a dictionary is perfect - it gives us O(1) access to any task's information using its taskId as the key. We store (userId, priority) as the value.

For maintaining sorted order, we need a structure that supports:

  • Insertion in sorted order
  • Removal of arbitrary elements
  • Access to the maximum element

A SortedList (balanced binary search tree) fits perfectly, providing O(log n) operations for all these needs.

The clever trick is how we store elements in the sorted list. Since we want the highest priority first but Python's sorted structures maintain ascending order, we store negative priorities (-priority). Similarly, when priorities are equal, we want the highest taskId first, so we also negate the taskId (-taskId). This transforms our "find maximum" problem into a "find minimum" problem, which naturally aligns with the sorted order.

By maintaining these two synchronized data structures, we achieve efficient operations: O(log n) for add, edit, and remove operations, and O(log n) for executing the top task.

Learn more about Heap (Priority Queue) patterns.

Solution Approach

The solution uses two synchronized data structures to efficiently manage tasks:

  1. Dictionary d: Maps taskId to (userId, priority) for O(1) lookups
  2. SortedList st: Maintains tasks in sorted order by (-priority, -taskId)

Implementation Details:

Initialization (__init__):

def __init__(self, tasks: List[List[int]]):
    self.d = {}
    self.st = SortedList()
    for task in tasks:
        self.add(*task)
  • Initialize empty dictionary and sorted list
  • Use the add method to process each initial task

Adding a Task (add):

def add(self, userId: int, taskId: int, priority: int) -> None:
    self.d[taskId] = (userId, priority)
    self.st.add((-priority, -taskId))
  • Store task information in dictionary with taskId as key
  • Add (-priority, -taskId) tuple to sorted list to maintain proper ordering

Editing Task Priority (edit):

def edit(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))
  • Retrieve current user and priority from dictionary
  • Remove old entry from sorted list using discard (won't raise error if not found)
  • Update dictionary with new priority
  • Add new entry to sorted list with updated priority

Removing a Task (rmv):

def rmv(self, taskId: int) -> None:
    _, priority = self.d[taskId]
    self.d.pop(taskId)
    self.st.remove((-priority, -taskId))
  • Get priority from dictionary (userId not needed)
  • Remove from dictionary using pop
  • Remove from sorted list using remove

Executing Top Priority Task (execTop):

def execTop(self) -> int:
    if not self.st:
        return -1
    taskId = -self.st.pop(0)[1]
    userId, _ = self.d[taskId]
    self.d.pop(taskId)
    return userId
  • Check if sorted list is empty, return -1 if no tasks
  • Pop the first element (highest priority due to negative values)
  • Extract taskId by negating the second element of the tuple
  • Get userId from dictionary
  • Remove task from dictionary
  • Return the userId

Time Complexity:

  • add: O(log n) for sorted list insertion
  • edit: O(log n) for removal and insertion in sorted list
  • rmv: O(log n) for sorted list removal
  • execTop: O(log n) for popping from sorted list
  • Space: O(n) for storing n tasks

The negative value trick (-priority, -taskId) ensures that the sorted list maintains tasks in descending order of priority and taskId, making the first element always the correct one to execute.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example to illustrate how the solution works.

Initial Setup:

tasks = [[1, 101, 3], [2, 102, 5], [1, 103, 3]]
tm = TaskManager(tasks)

After initialization:

  • Dictionary d: {101: (1, 3), 102: (2, 5), 103: (1, 3)}
  • SortedList st: [(-5, -102), (-3, -103), (-3, -101)]

Notice how the sorted list orders tasks:

  • Task 102 with priority 5 comes first (stored as -5)
  • Tasks 101 and 103 both have priority 3, but 103 has higher taskId, so (-3, -103) comes before (-3, -101)

Operation 1: Execute top priority task

result = tm.execTop()  # Returns 2
  • The first element in sorted list is (-5, -102)
  • Extract taskId: -(-102) = 102
  • Look up in dictionary: d[102] = (2, 5), so userId = 2
  • Remove task 102 from both structures
  • After: d = {101: (1, 3), 103: (1, 3)}, st = [(-3, -103), (-3, -101)]

Operation 2: Add a new task

tm.add(3, 104, 3)
  • Add to dictionary: d[104] = (3, 3)
  • Add to sorted list: (-3, -104)
  • After: d = {101: (1, 3), 103: (1, 3), 104: (3, 3)}, st = [(-3, -104), (-3, -103), (-3, -101)]
  • Note: Task 104 is now first among priority-3 tasks due to highest taskId

Operation 3: Edit task priority

tm.edit(101, 7)
  • Current info: d[101] = (1, 3)
  • Remove (-3, -101) from sorted list
  • Update dictionary: d[101] = (1, 7)
  • Add (-7, -101) to sorted list
  • After: d = {101: (1, 7), 103: (1, 3), 104: (3, 3)}, st = [(-7, -101), (-3, -104), (-3, -103)]
  • Task 101 is now the highest priority task

Operation 4: Execute top priority task again

result = tm.execTop()  # Returns 1
  • Pop (-7, -101) from sorted list
  • taskId = 101, userId = 1
  • After: d = {103: (1, 3), 104: (3, 3)}, st = [(-3, -104), (-3, -103)]

This example demonstrates how the negative value storage ensures correct priority ordering and how the two data structures work together to maintain efficient operations.

Solution Implementation

1from typing import List
2from sortedcontainers import SortedList
3
4
5class TaskManager:
6    def __init__(self, tasks: List[List[int]]):
7        """
8        Initialize the TaskManager with a list of tasks.
9        Each task is represented as [userId, taskId, priority].
10        """
11        # Dictionary to store task information: taskId -> (userId, priority)
12        self.task_info = {}
13      
14        # SortedList to maintain tasks ordered by priority (highest first) and taskId (highest first)
15        # Using negative values to achieve descending order
16        self.priority_queue = SortedList()
17      
18        # Add all initial tasks
19        for task in tasks:
20            self.add(task[0], task[1], task[2])
21
22    def add(self, userId: int, taskId: int, priority: int) -> None:
23        """
24        Add a new task to the system.
25      
26        Args:
27            userId: ID of the user who owns the task
28            taskId: Unique identifier for the task
29            priority: Priority level of the task (higher value = higher priority)
30        """
31        # Store task information in dictionary
32        self.task_info[taskId] = (userId, priority)
33      
34        # Add to sorted list with negative values for descending order
35        # Negative priority ensures higher priorities come first
36        # Negative taskId ensures higher taskIds come first when priorities are equal
37        self.priority_queue.add((-priority, -taskId))
38
39    def edit(self, taskId: int, newPriority: int) -> None:
40        """
41        Edit the priority of an existing task.
42      
43        Args:
44            taskId: ID of the task to edit
45            newPriority: New priority value for the task
46        """
47        # Retrieve current task information
48        user_id, old_priority = self.task_info[taskId]
49      
50        # Remove old entry from sorted list
51        self.priority_queue.discard((-old_priority, -taskId))
52      
53        # Update task information with new priority
54        self.task_info[taskId] = (user_id, newPriority)
55      
56        # Add updated entry to sorted list
57        self.priority_queue.add((-newPriority, -taskId))
58
59    def rmv(self, taskId: int) -> None:
60        """
61        Remove a task from the system.
62      
63        Args:
64            taskId: ID of the task to remove
65        """
66        # Retrieve task priority for removal from sorted list
67        _, priority = self.task_info[taskId]
68      
69        # Remove task from dictionary
70        self.task_info.pop(taskId)
71      
72        # Remove task from sorted list
73        self.priority_queue.remove((-priority, -taskId))
74
75    def execTop(self) -> int:
76        """
77        Execute the highest priority task and remove it from the system.
78      
79        Returns:
80            The userId of the executed task, or -1 if no tasks exist
81        """
82        # Check if there are any tasks to execute
83        if not self.priority_queue:
84            return -1
85      
86        # Pop the highest priority task (first element in sorted list)
87        # Extract taskId by negating the second element of the tuple
88        task_id = -self.priority_queue.pop(0)[1]
89      
90        # Get the userId of the task owner
91        user_id, _ = self.task_info[task_id]
92      
93        # Remove task from dictionary
94        self.task_info.pop(task_id)
95      
96        return user_id
97
98
99# Your TaskManager object will be instantiated and called as such:
100# obj = TaskManager(tasks)
101# obj.add(userId, taskId, priority)
102# obj.edit(taskId, newPriority)
103# obj.rmv(taskId)
104# param_4 = obj.execTop()
105
1class TaskManager {
2    // Map to store taskId -> [userId, priority]
3    private final Map<Integer, int[]> taskMap = new HashMap<>();
4  
5    // TreeSet to maintain tasks sorted by priority (descending) and taskId (descending)
6    // Format: [priority, taskId]
7    private final TreeSet<int[]> priorityQueue = new TreeSet<>((a, b) -> {
8        // If priorities are equal, sort by taskId in descending order
9        if (a[0] == b[0]) {
10            return b[1] - a[1];
11        }
12        // Sort by priority in descending order (higher priority first)
13        return b[0] - a[0];
14    });
15
16    /**
17     * Constructor to initialize the TaskManager with a list of tasks
18     * @param tasks List of tasks where each task contains [userId, taskId, priority]
19     */
20    public TaskManager(List<List<Integer>> tasks) {
21        for (List<Integer> task : tasks) {
22            add(task.get(0), task.get(1), task.get(2));
23        }
24    }
25
26    /**
27     * Add a new task to the system
28     * @param userId The user who owns the task
29     * @param taskId The unique identifier for the task
30     * @param priority The priority level of the task
31     */
32    public void add(int userId, int taskId, int priority) {
33        // Store task information in the map
34        taskMap.put(taskId, new int[] {userId, priority});
35      
36        // Add task to the priority queue
37        priorityQueue.add(new int[] {priority, taskId});
38    }
39
40    /**
41     * Edit the priority of an existing task
42     * @param taskId The task to be edited
43     * @param newPriority The new priority value for the task
44     */
45    public void edit(int taskId, int newPriority) {
46        // Retrieve existing task information
47        int[] taskInfo = taskMap.get(taskId);
48        int userId = taskInfo[0];
49        int oldPriority = taskInfo[1];
50      
51        // Remove old entry from priority queue
52        priorityQueue.remove(new int[] {oldPriority, taskId});
53      
54        // Add updated entry to priority queue
55        priorityQueue.add(new int[] {newPriority, taskId});
56      
57        // Update task information in the map
58        taskMap.put(taskId, new int[] {userId, newPriority});
59    }
60
61    /**
62     * Remove a task from the system
63     * @param taskId The task to be removed
64     */
65    public void rmv(int taskId) {
66        // Remove task from map and get its information
67        int[] taskInfo = taskMap.remove(taskId);
68        int priority = taskInfo[1];
69      
70        // Remove task from priority queue
71        priorityQueue.remove(new int[] {priority, taskId});
72    }
73
74    /**
75     * Execute the task with the highest priority and return the userId
76     * @return The userId of the executed task, or -1 if no tasks exist
77     */
78    public int execTop() {
79        // Check if there are any tasks to execute
80        if (priorityQueue.isEmpty()) {
81            return -1;
82        }
83      
84        // Remove and get the highest priority task
85        int[] topTask = priorityQueue.pollFirst();
86        int taskId = topTask[1];
87      
88        // Remove task from map and get user information
89        int[] taskInfo = taskMap.remove(taskId);
90        int userId = taskInfo[0];
91      
92        return userId;
93    }
94}
95
96/**
97 * Your TaskManager object will be instantiated and called as such:
98 * TaskManager obj = new TaskManager(tasks);
99 * obj.add(userId,taskId,priority);
100 * obj.edit(taskId,newPriority);
101 * obj.rmv(taskId);
102 * int param_4 = obj.execTop();
103 */
104
1class TaskManager {
2private:
3    // Map: taskId -> (userId, priority)
4    unordered_map<int, pair<int, int>> taskMap;
5  
6    // Set to maintain tasks sorted by priority (descending) and taskId (descending)
7    // Stores pairs of (-priority, -taskId) for automatic sorting
8    set<pair<int, int>> prioritySet;
9
10public:
11    /**
12     * Constructor: Initialize the task manager with initial tasks
13     * @param tasks: Vector of tasks where each task is [userId, taskId, priority]
14     */
15    TaskManager(vector<vector<int>>& tasks) {
16        for (const auto& task : tasks) {
17            add(task[0], task[1], task[2]);
18        }
19    }
20
21    /**
22     * Add a new task to the system
23     * @param userId: The user who owns the task
24     * @param taskId: Unique identifier for the task
25     * @param priority: Priority level of the task
26     */
27    void add(int userId, int taskId, int priority) {
28        // Store task information in the map
29        taskMap[taskId] = {userId, priority};
30      
31        // Insert into set with negative values for descending order
32        // Higher priority and higher taskId will come first
33        prioritySet.insert({-priority, -taskId});
34    }
35
36    /**
37     * Edit the priority of an existing task
38     * @param taskId: The task to edit
39     * @param newPriority: The new priority value
40     */
41    void edit(int taskId, int newPriority) {
42        // Get current task information
43        auto [userId, oldPriority] = taskMap[taskId];
44      
45        // Remove old entry from the priority set
46        prioritySet.erase({-oldPriority, -taskId});
47      
48        // Insert new entry with updated priority
49        prioritySet.insert({-newPriority, -taskId});
50      
51        // Update the task map with new priority
52        taskMap[taskId] = {userId, newPriority};
53    }
54
55    /**
56     * Remove a task from the system
57     * @param taskId: The task to remove
58     */
59    void rmv(int taskId) {
60        // Get task information before removal
61        auto [userId, priority] = taskMap[taskId];
62      
63        // Remove from priority set
64        prioritySet.erase({-priority, -taskId});
65      
66        // Remove from task map
67        taskMap.erase(taskId);
68    }
69
70    /**
71     * Execute the highest priority task
72     * @return: The userId of the executed task, or -1 if no tasks exist
73     */
74    int execTop() {
75        // Check if there are any tasks to execute
76        if (prioritySet.empty()) {
77            return -1;
78        }
79      
80        // Get the highest priority task (first element in set)
81        auto topTask = *prioritySet.begin();
82        prioritySet.erase(prioritySet.begin());
83      
84        // Extract taskId (negate to get original value)
85        int taskId = -topTask.second;
86      
87        // Get userId from the task map
88        int userId = taskMap[taskId].first;
89      
90        // Remove task from map
91        taskMap.erase(taskId);
92      
93        return userId;
94    }
95};
96
97/**
98 * Your TaskManager object will be instantiated and called as such:
99 * TaskManager* obj = new TaskManager(tasks);
100 * obj->add(userId,taskId,priority);
101 * obj->edit(taskId,newPriority);
102 * obj->rmv(taskId);
103 * int param_4 = obj->execTop();
104 */
105
1// Map: taskId -> [userId, priority]
2const taskMap: Map<number, [number, number]> = new Map();
3
4// Array to maintain tasks sorted by priority (descending) and taskId (descending)
5// Stores tuples of [priority, taskId]
6let priorityArray: [number, number][] = [];
7
8/**
9 * Initialize the task manager with initial tasks
10 * @param tasks - Array of tasks where each task is [userId, taskId, priority]
11 */
12function TaskManager(tasks: number[][]): void {
13    // Clear existing data
14    taskMap.clear();
15    priorityArray = [];
16  
17    // Add all initial tasks
18    for (const task of tasks) {
19        add(task[0], task[1], task[2]);
20    }
21}
22
23/**
24 * Add a new task to the system
25 * @param userId - The user who owns the task
26 * @param taskId - Unique identifier for the task
27 * @param priority - Priority level of the task
28 */
29function add(userId: number, taskId: number, priority: number): void {
30    // Store task information in the map
31    taskMap.set(taskId, [userId, priority]);
32  
33    // Add to priority array
34    priorityArray.push([priority, taskId]);
35  
36    // Sort array to maintain order: higher priority first, then higher taskId first
37    priorityArray.sort((a, b) => {
38        if (a[0] !== b[0]) {
39            return b[0] - a[0]; // Descending by priority
40        }
41        return b[1] - a[1]; // Descending by taskId
42    });
43}
44
45/**
46 * Edit the priority of an existing task
47 * @param taskId - The task to edit
48 * @param newPriority - The new priority value
49 */
50function edit(taskId: number, newPriority: number): void {
51    // Get current task information
52    const taskInfo = taskMap.get(taskId);
53    if (!taskInfo) return;
54  
55    const [userId, oldPriority] = taskInfo;
56  
57    // Find and remove the old entry from priority array
58    const indexToRemove = priorityArray.findIndex(
59        item => item[0] === oldPriority && item[1] === taskId
60    );
61    if (indexToRemove !== -1) {
62        priorityArray.splice(indexToRemove, 1);
63    }
64  
65    // Update the task map with new priority
66    taskMap.set(taskId, [userId, newPriority]);
67  
68    // Add new entry and re-sort
69    priorityArray.push([newPriority, taskId]);
70    priorityArray.sort((a, b) => {
71        if (a[0] !== b[0]) {
72            return b[0] - a[0]; // Descending by priority
73        }
74        return b[1] - a[1]; // Descending by taskId
75    });
76}
77
78/**
79 * Remove a task from the system
80 * @param taskId - The task to remove
81 */
82function rmv(taskId: number): void {
83    // Get task information before removal
84    const taskInfo = taskMap.get(taskId);
85    if (!taskInfo) return;
86  
87    const [userId, priority] = taskInfo;
88  
89    // Find and remove from priority array
90    const indexToRemove = priorityArray.findIndex(
91        item => item[0] === priority && item[1] === taskId
92    );
93    if (indexToRemove !== -1) {
94        priorityArray.splice(indexToRemove, 1);
95    }
96  
97    // Remove from task map
98    taskMap.delete(taskId);
99}
100
101/**
102 * Execute the highest priority task
103 * @returns The userId of the executed task, or -1 if no tasks exist
104 */
105function execTop(): number {
106    // Check if there are any tasks to execute
107    if (priorityArray.length === 0) {
108        return -1;
109    }
110  
111    // Get the highest priority task (first element in array)
112    const topTask = priorityArray.shift();
113    if (!topTask) return -1;
114  
115    const [priority, taskId] = topTask;
116  
117    // Get userId from the task map
118    const taskInfo = taskMap.get(taskId);
119    if (!taskInfo) return -1;
120  
121    const userId = taskInfo[0];
122  
123    // Remove task from map
124    taskMap.delete(taskId);
125  
126    return userId;
127}
128

Time and Space Complexity

Time Complexity:

  • __init__(tasks): O(n log n) where n is the number of tasks. Each task is added to the dictionary in O(1) and to the SortedList in O(log n), resulting in O(n log n) for all tasks.

  • add(userId, taskId, priority): O(log n) where n is the current number of tasks. Dictionary insertion is O(1), but adding to SortedList requires O(log n) for maintaining sorted order.

  • edit(taskId, newPriority): O(log n) where n is the current number of tasks. The operation involves:

    • Dictionary lookup: O(1)
    • Discarding from SortedList: O(log n) for finding + O(n) worst case for removal
    • Dictionary update: O(1)
    • Adding to SortedList: O(log n)
    • Overall: O(n) worst case, but typically O(log n) in practice
  • rmv(taskId): O(n) worst case where n is the current number of tasks. The operation involves:

    • Dictionary lookup: O(1)
    • Dictionary deletion: O(1)
    • Removing from SortedList: O(log n) for finding + O(n) for removal
    • Overall: O(n) due to the remove() operation
  • execTop(): O(log n) where n is the current number of tasks. Popping from the front of SortedList is O(log n), and dictionary operations are O(1).

Space Complexity:

  • Overall space complexity: O(n) where n is the number of tasks
  • Dictionary self.d: O(n) to store all task mappings
  • SortedList self.st: O(n) to store all task priorities and IDs
  • Total auxiliary space: O(n)

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Forgetting to Handle the Tie-Breaking Rule Correctly

Pitfall: When multiple tasks have the same priority, the problem requires choosing the one with the highest taskId. A common mistake is to use (priority, taskId) directly in the sorted list, which would give us the lowest taskId when priorities are equal.

Incorrect Implementation:

# Wrong: This would select lowest taskId when priorities are equal
self.priority_queue.add((-priority, taskId))  # INCORRECT!

Solution: Store both priority and taskId as negative values: (-priority, -taskId). This ensures that when the sorted list orders tuples, higher taskIds come first among tasks with the same priority.

2. Using remove() Instead of discard() in Edit Operation

Pitfall: In the edit() method, if there's any synchronization issue or the task was already removed, using remove() will raise a ValueError if the element is not found.

Problematic Code:

def edit(self, taskId: int, newPriority: int) -> None:
    userId, priority = self.task_info[taskId]
    self.priority_queue.remove((-priority, -taskId))  # May raise ValueError!
    # ...

Solution: Use discard() which silently does nothing if the element is not present:

self.priority_queue.discard((-priority, -taskId))  # Safe operation

3. Inconsistent Data Structure Updates

Pitfall: Forgetting to update both data structures (dictionary and sorted list) in sync. For example, removing from one but not the other.

Incorrect Implementation:

def rmv(self, taskId: int) -> None:
    # Forgot to get priority before removing from dictionary!
    self.task_info.pop(taskId)
    # Now we can't remove from sorted list because we lost the priority
    self.priority_queue.remove((-priority, -taskId))  # priority is undefined!

Solution: Always retrieve necessary information before modifying any data structure:

def rmv(self, taskId: int) -> None:
    _, priority = self.task_info[taskId]  # Get priority first
    self.task_info.pop(taskId)
    self.priority_queue.remove((-priority, -taskId))

4. Incorrect Extraction of TaskId in execTop()

Pitfall: Forgetting to negate the taskId when extracting it from the sorted list tuple.

Incorrect Implementation:

def execTop(self) -> int:
    if not self.priority_queue:
        return -1
    task_id = self.priority_queue.pop(0)[1]  # Wrong! This is negative
    # task_id is actually -taskId, will cause KeyError in dictionary lookup
    userId, _ = self.task_info[task_id]  # KeyError!

Solution: Remember to negate the taskId to get the original value:

task_id = -self.priority_queue.pop(0)[1]  # Correct: negate to get positive taskId

5. Not Checking for Empty Queue in execTop()

Pitfall: Attempting to pop from an empty sorted list will raise an IndexError.

Incorrect Implementation:

def execTop(self) -> int:
    # Dangerous: No check for empty queue
    task_id = -self.priority_queue.pop(0)[1]  # IndexError if empty!
    # ...

Solution: Always check if the queue is empty before attempting to pop:

def execTop(self) -> int:
    if not self.priority_queue:  # Check for empty queue
        return -1
    task_id = -self.priority_queue.pop(0)[1]
    # ...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More