Compute maximum concurrent trips from intervals
Company: Uber
Role: Data Scientist
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's skill in designing efficient algorithms for interval overlap counting, including event ordering, handling half-open interval edge cases, and reasoning about concurrent activity timing.
Part 1: Maximum Concurrent Trips and Earliest Time
Constraints
- 0 <= n <= 10^5
- 0 <= start < end <= 10^9
- Intervals are half-open: [start, end)
- If end == start for two trips, they do not overlap
- An O(n log n) time solution is expected
Examples
Input: [[0, 10], [5, 12], [11, 13], [2, 7]]
Expected Output: (3, 5)
Explanation: The maximum overlap is 3, first reached at time 5.
Input: [[1, 3], [3, 5]]
Expected Output: (1, 1)
Explanation: The intervals touch at 3 but do not overlap, so the maximum is 1.
Input: []
Expected Output: (0, None)
Explanation: No trips means no concurrency.
Input: [[4, 9]]
Expected Output: (1, 4)
Explanation: A single interval has maximum concurrency 1 starting at its own start.
Input: [[2, 6], [2, 5], [2, 4], [6, 8]]
Expected Output: (3, 2)
Explanation: Three trips start together at time 2.
Solution
def solution(trips):
n = len(trips)
if n == 0:
return (0, None)
starts = sorted(s for s, _ in trips)
ends = sorted(e for _, e in trips)
i = 0
j = 0
active = 0
best = 0
best_t = None
while i < n:
if j == n or starts[i] < ends[j]:
active += 1
if active > best:
best = active
best_t = starts[i]
i += 1
else:
active -= 1
j += 1
return (best, best_t)Time complexity: O(n log n). Space complexity: O(n).
Hints
- Sort all start times and end times separately, then sweep through them with two pointers.
- Because the intervals are half-open, when a start time equals an end time, process the end first.
Part 2: Earliest Continuous Range of Maximum Concurrency
Constraints
- 0 <= n <= 10^5
- 0 <= start < end <= 10^9
- Intervals are half-open: [start, end)
- If end == start for two trips, they do not overlap
- An O(n log n) time solution is expected
Examples
Input: [[0, 10], [5, 12], [11, 13], [2, 7]]
Expected Output: (3, 5, 7)
Explanation: The concurrency is 3 for the continuous range [5, 7).
Input: [[0, 2], [1, 3], [4, 6], [5, 7]]
Expected Output: (2, 1, 2)
Explanation: Maximum concurrency 2 happens on [1, 2) and [5, 6), so return the earliest one.
Input: []
Expected Output: (0, None, None)
Explanation: No trips means no maximum range.
Input: [[1, 2], [2, 3]]
Expected Output: (1, 1, 3)
Explanation: Even though the intervals only touch, the concurrency stays at 1 continuously from time 1 to 3.
Input: [[0, 10], [5, 8], [8, 12]]
Expected Output: (2, 5, 10)
Explanation: At time 8 one trip ends and another starts, but the concurrency remains 2 continuously on [5, 10).
Solution
def solution(trips):
if not trips:
return (0, None, None)
delta = {}
for s, e in trips:
delta[s] = delta.get(s, 0) + 1
delta[e] = delta.get(e, 0) - 1
times = sorted(delta)
active = 0
best = 0
for i, t in enumerate(times[:-1]):
active += delta[t]
if t < times[i + 1] and active > best:
best = active
active = 0
open_start = None
open_end = None
for i, t in enumerate(times[:-1]):
active += delta[t]
next_t = times[i + 1]
if active == best and t < next_t:
if open_start is None:
open_start = t
open_end = next_t
elif open_start is not None:
return (best, open_start, open_end)
if open_start is not None:
return (best, open_start, open_end)
return (0, None, None)Time complexity: O(n log n). Space complexity: O(n).
Hints
- The active-trip count only changes at interval boundaries, so sweep across sorted unique event times.
- Aggregate all changes at the same timestamp; if a trip ends and another starts at the same time, the maximum range may continue without a break.
Part 3: Maximum Concurrent Trips in a Start-Sorted Stream
Constraints
- 0 <= n <= 10^5
- 0 <= start < end <= 10^9
- Intervals are half-open: [start, end)
- The input is sorted by nondecreasing start time
- Use only O(k) extra space, where k is the number of active trips
Examples
Input: [[0, 10], [2, 7], [5, 12], [11, 13]]
Expected Output: (3, 5)
Explanation: The maximum number of active trips is 3, first reached when the trip starting at 5 arrives.
Input: []
Expected Output: (0, None)
Explanation: No trips means no concurrency.
Input: [[1, 4], [1, 3], [1, 2], [2, 5]]
Expected Output: (3, 1)
Explanation: Three trips are active at time 1.
Input: [[0, 1], [1, 2], [2, 3]]
Expected Output: (1, 0)
Explanation: Trips only touch at boundaries, so concurrency never exceeds 1.
Input: [[0, 10], [10, 20], [10, 15], [12, 18]]
Expected Output: (3, 12)
Explanation: The trip ending at 10 does not overlap the two trips starting at 10, and the maximum of 3 is first reached at time 12.
Solution
def solution(trips):
import heapq
if not trips:
return (0, None)
active_ends = []
best = 0
best_t = None
for s, e in trips:
while active_ends and active_ends[0] <= s:
heapq.heappop(active_ends)
heapq.heappush(active_ends, e)
if len(active_ends) > best:
best = len(active_ends)
best_t = s
return (best, best_t)Time complexity: O(n log k). Space complexity: O(k).
Hints
- Keep the end times of currently active trips in a min-heap.
- Before adding a new trip [s, e), remove every active trip with end <= s, because touching intervals do not overlap.