Quick Overview

Build a task scheduler that supports insertion, removal, and bounded popping in timestamp order, using smaller task IDs to break equal-timestamp ties.

Build a Removable Timestamp-Ordered Task Scheduler

Company: ByteDance

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

## Problem Implement a task scheduler with three operations: ```text addTask(taskId, timestamp) removeTask(taskId) popTasks(count) ``` `addTask` inserts one task. `removeTask` removes that task if it is currently scheduled. `popTasks(count)` removes and returns up to `count` scheduled task IDs in ascending order of start timestamp. When timestamps tie, smaller task IDs come first. Process a sequence of operations and return one array for every `pop` operation. ### Function Contract Implement `runTaskScheduler(operations)`, where an operation is: ```text ["add", taskId, timestamp] ["remove", taskId] ["pop", count] ``` Return an array of task-ID arrays, one per `pop`, in operation order. ### Constraints & Assumptions - `0 <= len(operations) <= 200,000`. - `taskId` and `timestamp` are integers in the JavaScript-safe range `[-(2^53 - 1), 2^53 - 1]` so their values and ordering are preserved identically in all four supported languages. - An `add` uses a task ID that is not currently scheduled. A previously removed or popped ID may be added again. - Removing an absent task is a no-op. - `count >= 0`; if fewer than `count` tasks remain, return and remove all of them. - A `pop` with `count = 0` returns an empty array and changes no state. ### Clarifying Questions to Ask - Does `pop` only inspect tasks or remove them? It removes every returned task. - How are equal timestamps ordered? By increasing task ID. - May removed task IDs be reused? Yes. - What happens when `remove` names an absent task? Nothing. ```hint Combine ordering with membership A min-heap gives the next timestamp, while a map or set records which task version is still active. ``` ```hint Make reused IDs safe If removal is lazy, attach a generation number to each heap entry so an old entry cannot remove a later task that reused the same ID. ``` ### Example ```text operations = [ ["add", 7, 30], ["add", 2, 10], ["add", 5, 10], ["remove", 2], ["pop", 2], ["pop", 1] ] ``` Return `[[5, 7], []]`. ### Evaluation Focus - Removes tasks returned by `pop` and never returns a removed task. - Applies the timestamp-and-ID ordering deterministically. - Handles stale heap entries and reuse of a task ID correctly. - Preserves exact integer identity and ordering throughout the stated cross-language safe range. - Runs each add or remove in `O(log n)` or better and returns `m` popped tasks in `O(m log n)` or better. ### Extensions to Discuss 1. How would an operation that changes a scheduled timestamp be supported? 2. What cleanup policy bounds stale heap entries after many removals? 3. How would the scheduler block until the earliest wall-clock timestamp becomes due?

Quick Answer: Build a task scheduler that supports insertion, removal, and bounded popping in timestamp order, using smaller task IDs to break equal-timestamp ties.

## Problem Implement a task scheduler with three operations: ```text addTask(taskId, timestamp) removeTask(taskId) popTasks(count) ``` `addTask` inserts one task. `removeTask` removes that task if it is currently scheduled. `popTasks(count)` removes and returns up to `count` scheduled task IDs in ascending order of start timestamp. When timestamps tie, smaller task IDs come first. Process a sequence of operations and return one array for every `pop` operation. ### Function Contract Implement `runTaskScheduler(operations)`, where an operation is: ```text ["add", taskId, timestamp] ["remove", taskId] ["pop", count] ``` Return an array of task-ID arrays, one per `pop`, in operation order. ### Constraints & Assumptions - `0 <= len(operations) <= 200,000`. - `taskId` and `timestamp` are integers in the JavaScript-safe range `[-(2^53 - 1), 2^53 - 1]` so their values and ordering are preserved identically in all four supported languages. - An `add` uses a task ID that is not currently scheduled. A previously removed or popped ID may be added again. - Removing an absent task is a no-op. - `count >= 0`; if fewer than `count` tasks remain, return and remove all of them. - A `pop` with `count = 0` returns an empty array and changes no state. ### Clarifying Questions to Ask - Does `pop` only inspect tasks or remove them? It removes every returned task. - How are equal timestamps ordered? By increasing task ID. - May removed task IDs be reused? Yes. - What happens when `remove` names an absent task? Nothing. ```hint Combine ordering with membership A min-heap gives the next timestamp, while a map or set records which task version is still active. ``` ```hint Make reused IDs safe If removal is lazy, attach a generation number to each heap entry so an old entry cannot remove a later task that reused the same ID. ``` ### Example ```text operations = [ ["add", 7, 30], ["add", 2, 10], ["add", 5, 10], ["remove", 2], ["pop", 2], ["pop", 1] ] ``` Return `[[5, 7], []]`. ### Evaluation Focus - Removes tasks returned by `pop` and never returns a removed task. - Applies the timestamp-and-ID ordering deterministically. - Handles stale heap entries and reuse of a task ID correctly. - Preserves exact integer identity and ordering throughout the stated cross-language safe range. - Runs each add or remove in `O(log n)` or better and returns `m` popped tasks in `O(m log n)` or better. ### Extensions to Discuss 1. How would an operation that changes a scheduled timestamp be supported? 2. What cleanup policy bounds stale heap entries after many removals? 3. How would the scheduler block until the earliest wall-clock timestamp becomes due?

Constraints

  • 0 <= len(operations) <= 200000.
  • Each operation is [add, taskId, timestamp], [remove, taskId], or [pop, count].
  • taskId and timestamp are integers in [-(2^53 - 1), 2^53 - 1], inclusive.
  • An add uses an ID that is not currently scheduled; an ID may be reused after removal or pop.
  • Removing an absent ID is a no-op.
  • count >= 0; pop returns and removes at most count live IDs.
  • Tasks are ordered by increasing timestamp, then increasing task ID.

Examples

Input: ([['add', 7, 30], ['add', 2, 10], ['add', 5, 10], ['remove', 2], ['pop', 2], ['pop', 1]],)

Expected Output: [[5, 7], []]

Explanation: Sample 1: task 2 is removed, then tasks 5 and 7 are popped by timestamp and ID.

Input: ([],)

Expected Output: []

Explanation: Sample 2: an empty operation stream produces no pop result arrays.

Hints

  1. Use a min-heap for timestamp-and-ID order and a separate map for current membership.
  2. Attach a new generation to every add so a stale entry for a reused ID cannot match the later live task.

Loading coding console...