Bill Deliveries with Historical Rates and Deferred Rounding
Company: Rippling
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Technical Screen
Implement delivery billing with driver rate histories, duplicate-delivery protection, and exact accumulation before rounding.
Implement `delivery_billing(operations: string[][], rounding: string) -> string[]`, returning one result string per operation.
### Operations
- `["ADD",driverId,hourlyRate]`: add a new driver with an initial rate effective at time 0; return `OK`.
- `["UPDATE",driverId,newRate,effectiveTime]`: add a rate change; return `OK`.
- `["DELIVERY",deliveryId,driverId,start,end]`: record a delivery and its charge; return `OK` when recorded, or `IGNORED` for a duplicate already-recorded ID or a duration exceeding three hours.
- `["TOTAL"]`: return the cumulative charge formatted as dollars with exactly two fractional digits.
### Constraints & Assumptions
- At most 100000 operations. IDs are nonempty ASCII identifiers. ADD IDs are new, and every referenced driver exists. All times are integer seconds from 0 through 1000000000, with `0 <= start <= end`.
- Rates are nonnegative dollar strings with exactly two decimal places and are at most `10000.00` per hour.
- Delivery IDs are global across drivers. A recorded ID is ignored on every later DELIVERY even if its payload differs. An over-three-hour delivery is ignored without reserving its ID; this invalid-ID policy is an explicit practice choice.
- Exactly three hours is valid. Overlapping deliveries for the same driver are charged independently. Zero-duration deliveries are recorded with zero cost.
- Use the rate whose effective time is the greatest value not exceeding the delivery's start. A later operation at the same effective time replaces that rate for future lookups. Out-of-order effective times are allowed.
- The entire delivery uses its start-time rate; do not split at a rate change. Once recorded, its charge never changes after later rate updates, including backdated updates.
- Preserve fractional cents internally and round only when TOTAL returns. TOTAL must not mutate the accumulated exact amount.
- `rounding` is `HALF_UP` or `HALF_EVEN`. The source did not settle exact-half-cent ties, so this practice parameter makes both policies explicit: ties round upward for HALF_UP and to the even cent for HALF_EVEN. All amounts are nonnegative.
- Use integer arithmetic: a rate in cents multiplied by seconds gives an exact numerator with denominator 3600 cents. The stated bounds fit signed 64-bit arithmetic for the total numerator.
### Examples
```text
operations = [["ADD","d","15.15"],["DELIVERY","a","d","0","5400"],
["TOTAL"],["DELIVERY","b","d","5400","7200"],["TOTAL"],
["DELIVERY","a","d","0","5400"],["TOTAL"]]
rounding = "HALF_UP"
result = ["OK","OK","22.73","OK","30.30","IGNORED","30.30"]
```
The first delivery costs exactly 22.725 dollars and the second 7.575 dollars. Their exact sum is 30.30, not the sum of individually rounded charges. For the first TOTAL alone, HALF_EVEN would return 22.72. Querying between deliveries does not change the final sum.
Explain historical-rate lookup, duplicate handling, and the distinction among numeric representation, rounding time, and tie rule. For the reported debugging follow-up, describe how you would isolate a failing test: compare exact per-delivery charges, selected rate versions, duplicate IDs, and the final formatting step rather than labeling every discrepancy a floating-point issue.
```hint Keep the common denominator
All durations are integer seconds and all rates are integer cents per hour. Sum exact integer numerators, then round the final quotient once per query.
```
Overview: Bill deliveries with start-time historical rates, duplicate suppression, overlapping jobs, exact sub-cent accumulation, and configurable final half-up or half-even rounding.
Read the full Rippling Software Engineer interview experience this question came from