Find global GPU idle intervals
Company: Fireworks Ai
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates competency in interval reasoning, managing overlapping time ranges across distributed resources, designing online data structures for streaming task arrivals, and performing algorithmic time/space complexity analysis.
Find Global GPU Idle Intervals (Batch)
Constraints
- 1 <= number of tasks <= 10^5 (or 0 for an empty list)
- start < end for every task
- Timestamps are integers and may be negative
- Tasks may overlap on the same or different nodes and arrive unsorted
Examples
Input: ([(1, 3, 0), (5, 8, 1)],)
Expected Output: [(3, 5)]
Explanation: Fleet busy on [1,3] and [5,8]; idle on the gap (3,5).
Input: ([(1, 3, 0), (2, 6, 1), (8, 10, 0)],)
Expected Output: [(6, 8)]
Explanation: Overlapping tasks 1-3 and 2-6 merge to cover [1,6]; then 8-10. The only idle gap is (6,8).
Input: ([(1, 5, 0), (5, 9, 1)],)
Expected Output: []
Explanation: One task ends at 5 exactly as the next starts; touching intervals leave no idle time.
Input: ([(0, 10, 0)],)
Expected Output: []
Explanation: A single task covers the whole inferred range, so there is no idle time.
Input: ([],)
Expected Output: []
Explanation: No tasks means no inferred time range and no idle intervals.
Input: ([(1, 2, 0), (4, 5, 1), (7, 9, 2)],)
Expected Output: [(2, 4), (5, 7)]
Explanation: Three separated tasks produce two idle gaps: (2,4) and (5,7).
Input: ([(-5, -2, 0), (0, 3, 1)],)
Expected Output: [(-2, 0)]
Explanation: Negative timestamps are handled the same way; idle gap is (-2,0).
Hints
- Idle time is a global property: collapse all nodes into one fleet-wide count of active tasks. The node_id does not affect whether the fleet is idle.
- Convert each task into two events: +1 at start, -1 at end. Sweep timestamps in order while maintaining a running count of active tasks.
- When sorting ties, process end events (-1) before start events (+1) at the same timestamp so touching intervals don't create a spurious idle gap.
- Whenever the count is 0 between two consecutive distinct event timestamps, that span is a maximal idle interval.
Find Global GPU Idle Intervals (Streaming)
Constraints
- 1 <= number of operations <= 10^5
- For add ops: start < end; timestamps are integers and may be negative
- Tasks may arrive out of order and may overlap
- node_id does not affect idle computation (fleet-wide busy union)
Examples
Input: ([["add", 1, 3, 0], ["add", 5, 8, 1], ["get"]],)
Expected Output: [[(3, 5)]]
Explanation: After adding both tasks, the single idle gap between busy [1,3] and [5,8] is (3,5).
Input: ([["add", 5, 8, 1], ["add", 1, 3, 0], ["get"]],)
Expected Output: [[(3, 5)]]
Explanation: Tasks arrive out of order but the merged busy set is the same; idle is still (3,5).
Input: ([["add", 1, 3, 0], ["get"], ["add", 2, 6, 1], ["get"], ["add", 8, 10, 0], ["get"]],)
Expected Output: [[], [], [(6, 8)]]
Explanation: First get: only one interval, no gap. Second get: 1-3 and 2-6 merge to [1,6], still no gap. Third get: adding 8-10 creates idle gap (6,8).
Input: ([["add", 1, 5, 0], ["add", 5, 9, 1], ["get"]],)
Expected Output: [[]]
Explanation: Touching intervals [1,5] and [5,9] merge into [1,9] with no idle time.
Input: ([["get"]],)
Expected Output: [[]]
Explanation: Querying an empty stream yields no idle intervals.
Input: ([["add", 1, 2, 0], ["add", 7, 9, 2], ["add", 4, 5, 1], ["get"]],)
Expected Output: [[(2, 4), (5, 7)]]
Explanation: Three disjoint tasks (added out of order) leave two idle gaps: (2,4) and (5,7).
Input: ([["add", 1, 4, 0], ["add", 6, 9, 1], ["add", 3, 7, 2], ["get"]],)
Expected Output: [[]]
Explanation: The third task 3-7 bridges the gap between [1,4] and [6,9], merging everything into [1,9] with no idle time.
Hints
- Idle intervals are the complement of the union of all busy intervals, so maintain the merged set of busy intervals incrementally rather than recomputing from scratch.
- On addTask, find every existing interval that overlaps or touches the new one, absorb them into a single interval, and replace them — classic merge-interval insertion.
- Keep busy intervals sorted and disjoint (merge touching ones too). Then getIdleIntervals is just the strict gaps between consecutive busy intervals.
- For best per-op complexity use an ordered map keyed by start; locate the insertion point in O(log k) and remove swallowed intervals in O(m).