Implement tiered shipping calculator
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Implement in JavaScript a shipping-cost calculator with three progressively richer pricing models based on a configuration object keyed by destination.
1) Flat per‑unit price: given config[destination] = { unitPrice }, return unitPrice * quantity.
2) Tiered per‑unit pricing: given config[destination] = { tiers: [ { upTo: q1, unitPrice: p1 }, { upTo: q2, unitPrice: p2 }, ..., { upTo: Infinity, unitPrice: pk } ] }, compute the total by applying each tier only to the items that fall within that tier’s range; treat each upTo as inclusive and accumulate across tiers.
3) Flat base for the first n items plus tiers afterward: given config[destination] = { baseFlat: { upTo: n, amount: F }, tiers: [...] }, charge F once for quantities 1..n; for quantities > n, charge F for the first n items and then apply tiered pricing starting from item n+1. Carefully avoid off‑by‑one mistakes at n and other tier boundaries. Define the function signature calculateShipping(destination, quantity, config) and describe tests for edge cases (quantity 0, exactly at cutoffs, unknown location, negative inputs, floating‑point handling).
Quick Answer: Implement tiered shipping calculator evaluates algorithm design, data structures, correctness, complexity, edge cases, and implementation details in a realistic interview setting. A strong answer states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Implement `calculateShipping(destination, quantity, config)` where `config[destination]` selects one of three progressively richer pricing models:
1. **Flat per-unit**: `{ unitPrice }` -> `unitPrice * quantity`.
2. **Tiered per-unit (graduated)**: `{ tiers: [ { upTo, unitPrice }, ... ] }`. Apply each tier only to the items that fall within its range, treating each `upTo` as inclusive and accumulating across tiers (the last tier's `upTo` is an unbounded sentinel such as Infinity / a very large number).
3. **Flat base then tiers**: `{ baseFlat: { upTo: n, amount: F }, tiers: [...] }`. Charge `F` once for quantities 1..n; for quantities > n, charge `F` for the first n items and then apply tiered pricing starting from item n+1.
Watch the boundaries carefully (the n+1 transition and each tier `upTo`). For an unknown destination, return null/None; for quantity <= 0, return 0.
Constraints
- destination is a string; quantity is an integer (may be 0 or negative).
- Exactly one of unitPrice / tiers / baseFlat+tiers is present per destination.
- Tiers are sorted ascending by upTo; the final tier's upTo is unbounded (Infinity or a large sentinel).
- Each upTo is inclusive; tiers are graduated (marginal), not flat-rate-of-the-whole-order.
- Unknown destination returns null/None; quantity <= 0 returns 0.
Examples
Input: ('US', 3, {'US': {'unitPrice': 5.0}})
Expected Output: 15.0
Explanation: Flat model: unitPrice 5.0 x 3 units = 15.0.
Input: ('US', 0, {'US': {'unitPrice': 5.0}})
Expected Output: 0.0
Explanation: Edge: quantity 0 always costs 0.0 regardless of model.
Hints
- Dispatch on the shape of config[destination]: presence of unitPrice vs baseFlat vs tiers.
- For graduated tiers, track the previous tier's upTo; the current tier covers items (prev+1 .. min(upTo, quantity)).
- For the baseFlat model, charge F once, then start tier accounting at item n+1 — the classic off-by-one is charging item n twice or skipping item n+1.
- Handle quantity 0 / negative and unknown destination before touching tiers.