Compute peak busy dashers with overlaps
Company: Rippling
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: This question evaluates skills in interval-overlap reasoning, sweep-line algorithm design, event creation and deduplication, comparator and tie-breaking subtleties, and asymptotic time/space complexity analysis within the Coding & Algorithms domain.
Part 1: Peak Busy Dashers with Overlapping Orders
Constraints
- 0 <= len(logs) <= 200000
- 0 <= dasherId <= 10^9
- 0 <= startTime < endTime <= 10^9
- endTime is exclusive
Examples
Input: [[1, 1, 5], [1, 2, 6], [2, 4, 7]]
Expected Output: 2
Explanation: Dasher 1 is busy continuously from 1 to 6 after merging its overlapping orders. Dasher 2 overlaps from 4 to 6, so the peak is 2.
Input: [[1, 1, 3], [2, 3, 5]]
Expected Output: 1
Explanation: Because endTime is exclusive, the first order ends before the second begins at time 3.
Input: []
Expected Output: 0
Explanation: No logs means no busy dashers.
Input: [[5, 10, 12]]
Expected Output: 1
Explanation: A single order means exactly one busy dasher.
Input: [[1, 1, 2], [1, 2, 3], [2, 2, 4]]
Expected Output: 2
Explanation: Dasher 1 is busy continuously across back-to-back orders, and overlaps with dasher 2 from 2 to 3.
Solution
def solution(logs):
from collections import defaultdict
by_dasher = defaultdict(list)
for dasher_id, start, end in logs:
if start < end:
by_dasher[dasher_id].append((start, end))
merged = []
for intervals in by_dasher.values():
intervals.sort()
cur_start, cur_end = intervals[0]
for start, end in intervals[1:]:
if start <= cur_end:
if end > cur_end:
cur_end = end
else:
merged.append((cur_start, cur_end))
cur_start, cur_end = start, end
merged.append((cur_start, cur_end))
events = []
for start, end in merged:
events.append((start, 1))
events.append((end, -1))
events.sort(key=lambda x: (x[0], x[1]))
busy = 0
best = 0
for _, delta in events:
busy += delta
if busy > best:
best = busy
return best
Time complexity: O(n log n). Space complexity: O(n).
Hints
- First combine each dasher's intervals so overlapping or touching intervals become one busy block.
- After merging per dasher, the problem becomes a standard interval overlap sweep.
Part 2: Sweep-Line Busy Dashers in O(n log n)
Constraints
- 0 <= len(logs) <= 200000
- 0 <= dasherId <= 10^9
- 0 <= startTime < endTime <= 10^9
- You should target O(n log n) time
Examples
Input: [[1, 1, 4], [1, 1, 3], [2, 2, 5]]
Expected Output: 2
Explanation: Dasher 1 starts two orders at time 1 but still counts as only one busy dasher. Dasher 2 overlaps later, so the peak is 2.
Input: [[1, 1, 3], [1, 3, 5], [2, 3, 4]]
Expected Output: 2
Explanation: At time 3, dasher 1's first order ends before its second begins. Dasher 2 also starts at 3, so the peak becomes 2.
Input: [[1, 1, 5], [1, 2, 6], [1, 4, 7]]
Expected Output: 1
Explanation: All orders belong to the same dasher, so the busy count never exceeds 1.
Input: []
Expected Output: 0
Explanation: No events means the peak is 0.
Input: [[1, 1, 2], [2, 2, 3], [3, 2, 4]]
Expected Output: 2
Explanation: The order ending at time 2 is processed before the two starts at time 2, so the peak is 2.
Solution
def solution(logs):
from collections import defaultdict
events = []
for dasher_id, start, end in logs:
if start < end:
events.append((start, 1, dasher_id))
events.append((end, -1, dasher_id))
events.sort(key=lambda x: (x[0], x[1], x[2]))
active_orders = defaultdict(int)
busy = 0
best = 0
for _, delta, dasher_id in events:
if delta == 1:
if active_orders[dasher_id] == 0:
busy += 1
active_orders[dasher_id] += 1
else:
active_orders[dasher_id] -= 1
if active_orders[dasher_id] == 0:
busy -= 1
del active_orders[dasher_id]
if busy > best:
best = busy
return best
Time complexity: O(n log n). Space complexity: O(n).
Hints
- Sort events by (time, delta, dasherId) if you encode end as -1 and start as +1.
- Multiple starts for the same dasher at the same time should not raise the busy count more than once; track active orders per dasher.
Part 3: Correctly Sort Sweep-Line Events
Constraints
- 0 <= len(events) <= 200000
- 0 <= dasherId <= 10^9
- 0 <= time <= 10^9
- delta is either -1 or 1
Examples
Input: [[2, 5, 1], [1, 3, 1], [1, 5, -1]]
Expected Output: [[1, 3, 1], [1, 5, -1], [2, 5, 1]]
Explanation: Time 3 comes before time 5. At time 5, the end event comes before the start event.
Input: [[2, 4, 1], [1, 4, -1], [3, 4, 1]]
Expected Output: [[1, 4, -1], [2, 4, 1], [3, 4, 1]]
Explanation: All events share the same time, so delta decides first and dasherId breaks the remaining tie.
Input: []
Expected Output: []
Explanation: Sorting an empty list returns an empty list.
Input: [[7, 2, -1]]
Expected Output: [[7, 2, -1]]
Explanation: A single event is already sorted.
Input: [[3, 1, 1], [2, 1, 1], [1, 1, -1]]
Expected Output: [[1, 1, -1], [2, 1, 1], [3, 1, 1]]
Explanation: Same time for all events: end before starts, then smaller dasherId first.
Solution
def solution(events):
return sorted(events, key=lambda x: (x[1], x[2], x[0]))
Time complexity: O(n log n). Space complexity: O(n).
Hints
- The sweep-line must move through time globally, so time has to be the first sort key.
- When two events share the same time, an end event should come before a start event because endTime is exclusive.
Part 4: Peak Concurrent Orders When Dashers Cannot Overlap Orders
Constraints
- 0 <= len(logs) <= 200000
- 0 <= dasherId <= 10^9
- 0 <= startTime < endTime <= 10^9
- Orders for the same dasher do not overlap
Examples
Input: [[1, 1, 4], [2, 2, 5], [3, 3, 6]]
Expected Output: 3
Explanation: All three orders overlap between times 3 and 4.
Input: [[1, 1, 3], [2, 3, 5], [3, 5, 7]]
Expected Output: 1
Explanation: Because endTime is exclusive, these intervals only touch and never overlap.
Input: []
Expected Output: 0
Explanation: No orders means no concurrency.
Input: [[1, 1, 10], [2, 2, 3], [3, 2, 3], [4, 3, 4]]
Expected Output: 3
Explanation: At times in [2, 3), orders 1, 2, and 3 are all active.
Input: [[9, 5, 8]]
Expected Output: 1
Explanation: A single order gives a peak of 1.
Solution
def solution(logs):
events = []
for _, start, end in logs:
if start < end:
events.append((start, 1))
events.append((end, -1))
events.sort(key=lambda x: (x[0], x[1]))
current = 0
best = 0
for _, delta in events:
current += delta
if current > best:
best = current
return best
Time complexity: O(n log n). Space complexity: O(n).
Hints
- You no longer need per-dasher active counts, because each order can be counted directly.
- Use the standard interval sweep: add +1 at starts and -1 at ends, with ends processed before starts at the same time.