Implement Interval Overrides and Top-K Strings
CrusoeSoftware Engineer · OnsiteLast updated
Implement interval override logic for half-open ranges and calculate the top-k labels based on total active duration with lexicographical tie-breaking.
Problem Statement
You are monitoring compute resources where tasks or configurations are assigned to time windows. Each assignment specifies a half-open time interval [start, end) and an associated string label.
Assignments arrive sequentially. When a new interval is added, it overrides any existing intervals (or parts of intervals) that it overlaps with. Existing intervals may be completely replaced, clipped at the ends, or split into two disconnected segments.
Implement the function top_k_interval_labels(intervals: list[tuple[int, int, str]], k: int) -> list[str] which:
- Applies the list of intervals sequentially, allowing later intervals to override earlier ones.
- Computes the total non-overlapping duration assigned to each unique label across the final timeline.
- Returns the top
klabels with the greatest total duration, ordered from highest duration to lowest. If two labels have identical duration, tie-break alphabetically in ascending order ('a'before'b').
If there are fewer than k unique labels with duration greater than 0, return all of them in the specified order.
Function Signature
def top_k_interval_labels(intervals: list[tuple[int, int, str]], k: int) -> list[str]:
pass
Examples
Example 1
Input:
intervals = [
(0, 10, "alpha"),
(5, 8, "beta"),
(2, 6, "gamma")
]
k = 2
Output: ["alpha", "gamma"]
Explanation:
- Initially: [0, 10) is "alpha" (duration 10).
- After (5, 8, "beta"): [0, 5) is "alpha", [5, 8) is "beta", [8, 10) is "alpha".
- After (2, 6, "gamma"): "gamma" overrides [2, 6).
Timeline becomes:
- [0, 2): "alpha" (duration 2)
- [2, 6): "gamma" (duration 4)
- [6, 8): "beta" (duration 2)
- [8, 10): "alpha" (duration 2)
Final durations:
- "alpha": 2 + 2 = 4
- "gamma": 4
- "beta": 2
Both "alpha" and "gamma" have duration 4. Due to lexicographical tie-break, "alpha" comes before "gamma". The top 2 are ["alpha", "gamma"].
Example 2
Input:
intervals = [
(1, 5, "A"),
(0, 10, "B")
]
k = 1
Output: ["B"]
Explanation:
Interval (0, 10, "B") completely covers (1, 5, "A"). Final durations are "B": 10, "A": 0. The top 1 is ["B"].
Constraints
0 <= len(intervals) <= 20000 <= start < end <= 10^91 <= len(label) <= 30(lowercase and uppercase ASCII characters)1 <= k <= 1000
Edge Cases
- An interval completely enclosing or wiping out previous intervals.
- An override splitting an existing interval into two.
- Labels with 0 final duration should not be included in the output.
kgreater than the number of surviving labels.
Hints
Hint 1
Consider processing overrides sequentially by maintaining a list of disjoint labeled intervals and modifying, splitting, or removing them as each new interval arrives.
Hint 2
Alternatively, since coordinate compression or critical point splitting (boundary points) can create disjoint atomic segments, you can track which interval was the latest to cover each segment.
Hint 3
After computing each label's total active duration, sort using a tuple key `(-duration, label)` and slice up to `k`.
Follow-up questions
- How would you optimize this if there were 10^5 intervals added dynamically via a streaming API?
- Could an interval tree, segment tree, or balanced BST maintain the active timeline in `O(n log n)` time?
- How would the solution change if we needed to query top-k labels over a specific query window `[query_start, query_end)`?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.