Katkat

Implement Courier Delivery Cost Tracking

RipplingSoftware Engineer · Technical Screen

Last updated

Design an in-memory billing system that tracks courier pay rates over time and calculates prorated delivery costs across half-open time intervals.

Problem Statement

You are tasked with building a billing tracker for an on-demand courier platform. Couriers are paid based on hourly rates that can change over time. Each delivery is logged as a half-open time interval [start_time, end_time) in seconds.

Implement the CourierDeliveryTracker class with the following methods:

  • set_rate(courier_id: str, timestamp: int, hourly_rate_cents: int) -> None Sets the courier's hourly rate (in cents) starting from timestamp (inclusive). This rate remains in effect until a later rate is set for that courier. Timestamps for a given courier may not necessarily arrive in chronological order.

  • record_delivery(delivery_id: str, courier_id: str, start_time: int, end_time: int) -> None Records a delivery completed by courier_id during [start_time, end_time) where start_time int Calculates the total cost (in cents) for the specified delivery. If the delivery spans multiple rate periods, prorate the pay according to the time spent in each rate period. The exact prorated cost for d seconds at rate r cents/hour is d * r / 3600. Sum all unrounded segment costs, then round half up to the nearest cent: math.floor(total + 0.5).

  • get_courier_payout(courier_id: str, start_time: int, end_time: int) -> int Returns the total earnings for courier_id across all deliveries that overlap with the query window [start_time, end_time). For deliveries that only partially overlap with the query window, only count the overlapping portion. Deliveries for a single courier do not overlap with each other.

Example

tracker = CourierDeliveryTracker()

# Courier C1 starts at $18.00/hr (1800 cents/hr) at t = 0
tracker.set_rate("C1", 0, 1800)

# Courier C1 gets a raise to $24.00/hr (2400 cents/hr) at t = 3600
tracker.set_rate("C1", 3600, 2400)

# Delivery D1 spans t = 1800 to t = 5400 (1 hour under 1800, 0.5 hours under 2400)
tracker.record_delivery("D1", "C1", 1800, 5400)

# Cost: (1800s * 1800 / 3600) + (1800s * 2400 / 3600) = 900 + 1200 = 2100 cents
print(tracker.get_delivery_cost("D1")) # Output: 2100

# Payout for window [3600, 7200)
# Overlap with D1 is [3600, 5400) (1800s at 2400 cents/hr = 1200 cents)
print(tracker.get_courier_payout("C1", 3600, 7200)) # Output: 1200

Constraints

  • Timestamps are non-negative integers: 0 = 0
  • For every delivery, start_time >= min(timestamp) among all rate changes for that courier.
  • Up to 10^4 calls across all methods.
  • Each delivery_id is unique.

Hints

Hint 1

Maintain each courier's rate history as a sorted list of (timestamp, rate) tuples to enable binary search (bisect) for any given point in time.

Hint 2

To calculate cost across an interval [start, end), find all sub-intervals created by rate change timestamps that fall within [start, end) and compute the duration of each slice.

Hint 3

For get_courier_payout, intersect each courier's deliveries with the requested [start_time, end_time) window before evaluating the cost of each overlapping slice.

Follow-up questions

  • How would you optimize `get_courier_payout` if there are millions of historical deliveries per courier?
  • How would your interval intersection logic change if couriers could fulfill multiple overlapping deliveries concurrently (e.g., pooled deliveries)?
  • How would you handle non-linear billing rules, such as overtime pay kicking in after 8 hours in a rolling 24-hour window?