Courier Delivery Cost Tracker
RipplingSoftware Engineer · Technical ScreenLast updated
Design a stateful tracker class to record courier delivery intervals and earnings, query running courier payouts, and calculate peak concurrent active deliveries within a specific time window.
Courier Delivery Cost Tracker
You are building a backend service for an on-demand logistics platform to track courier activity and delivery payouts. Design a class CourierCostTracker that records delivery shifts, maintains courier balances, and analyzes peak delivery concurrency.
Each delivery takes place over a half-open time interval [start_time, end_time) (meaning the courier is active from start_time up until, but not including, end_time) and incurs a set delivery payout.
Implement the CourierCostTracker class:
CourierCostTracker(): Initializes the tracker.record_delivery(courier_id: str, start_time: int, end_time: int, fee: int) -> None: Records a completed delivery for couriercourier_idactive during[start_time, end_time)with an associated payout offee.get_courier_total(courier_id: str) -> int: Returns the total cumulative payout earned bycourier_id. Ifcourier_idhas no recorded deliveries, return0.get_peak_concurrent(window_start: int, window_end: int) -> int: Returns the maximum number of deliveries active at any single point in timetwithin the query window[window_start, window_end). Deliveries that overlap with the window should be counted only for the portion of time that falls strictly within[window_start, window_end).
Constraints
0 <= start_time < end_time <= 10^90 <= window_start < window_end <= 10^91 <= fee <= 10^5courier_idconsists of lowercase English letters and digits, length between 1 and 30.- At most
2,000calls torecord_deliveryandget_peak_concurrentcombined. - At most
10,000calls toget_courier_total.
Example 1
tracker = CourierCostTracker()
tracker.record_delivery("c1", 10, 30, 25)
tracker.record_delivery("c2", 20, 50, 40)
tracker.record_delivery("c1", 40, 60, 30)
# c1 earned 25 + 30 = 55
assert tracker.get_courier_total("c1") == 55
# c3 has no records
assert tracker.get_courier_total("c3") == 0
# In window [15, 45):
# - Delivery 1 [10, 30) is active in window during [15, 30)
# - Delivery 2 [20, 50) is active in window during [20, 45)
# - Delivery 3 [40, 60) is active in window during [40, 45)
# Peak concurrency occurs between time 20 and 30 (c1, c2), and between 40 and 45 (c2, c1), max is 2.
assert tracker.get_peak_concurrent(15, 45) == 2
# In window [30, 40), only Delivery 2 [20, 50) is active. Peak is 1.
assert tracker.get_peak_concurrent(30, 40) == 1
# In window [70, 100), no deliveries overlap. Peak is 0.
assert tracker.get_peak_concurrent(70, 100) == 0
Example 2
tracker = CourierCostTracker()
tracker.record_delivery("c1", 10, 20, 15)
tracker.record_delivery("c2", 20, 30, 15)
# Because intervals are half-open [10, 20) and [20, 30), they do not overlap at t = 20.
assert tracker.get_peak_concurrent(0, 50) == 1
Hints
Hint 1
Use a hash map to maintain running cumulative earnings per courier so that `get_courier_total` runs in O(1) time.
Hint 2
For `get_peak_concurrent`, filter deliveries that overlap with the query window by checking if `max(start_time, window_start) < min(end_time, window_end)`.
Hint 3
Transform each overlapping delivery interval into a pair of sweep-line events `(+1 at start, -1 at end)` clipped to the query window, then sort events by timestamp to find the maximum prefix sum.
Follow-up questions
- If `get_peak_concurrent` was called millions of times on historical, immutable delivery data, how would you optimize queries? (e.g., segment trees or coordinate compression with range maximum query structures).
- How would your design change if deliveries could be canceled or modified after being recorded?
- Suppose couriers can have multiple assignments simultaneously, but you need to return the peak number of unique couriers active at the same time rather than peak deliveries. How would you solve that?
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.