Calculate Inventory Purchases with Buy-X-Get-Y-Free Coupons
Company: Instacart
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: easy
Interview Round: Onsite
Compute the total price of a requested quantity of one inventory item, then support an optional buy-X-get-Y-free coupon for that item.
Implement `purchase_total(inventory: string[][], item: string, quantity: int, buy: int, free: int) -> string`.
### Constraints & Assumptions
These coupon and error semantics are explicit practice choices where the report is incomplete. Quantity is the total number of units the customer receives, including any free units. For each complete group of `buy + free` units, charge for `buy`; any remaining units are charged up to `buy`. Thus with buy 5/get 2, quantities 3, 6, and 7 pay for 3, 5, and 5 units respectively. No free units are added beyond the requested quantity.
- Each inventory row is `[name,stock,unitPrice]`; names are unique nonempty ASCII identifiers. Stock is a nonnegative integer string. Unit price is a nonnegative decimal string with exactly two digits after the point.
- At most 1000 inventory rows, stock and quantity at most 1000000, and unit price at most `1000000.00`. Quantity is nonnegative.
- `buy == 0` and `free == 0` means no coupon. Otherwise `1 <= buy <= 1000000` and `0 <= free <= 1000000`.
- Return `UNKNOWN_ITEM` if the item does not exist. Otherwise return `OUT_OF_STOCK` if quantity exceeds stock. No inventory mutation occurs.
- On success return the total with exactly two fractional digits and no currency symbol. Parse and calculate using integer cents, not binary floating point.
### Examples
```text
inventory = [["A","50","0.25"],["B","10","1.50"]]
item = "A", quantity = 7, buy = 5, free = 2
result = "1.25"
```
For the same item, quantity 3 costs `0.75`; quantity 0 costs `0.00`; quantity 51 returns `OUT_OF_STOCK`. Without a coupon, seven units cost `1.75`.
Explain how the function avoids decimal rounding errors and why an incomplete qualifying purchase cannot receive the full advertised free quantity. In an interview, clarify whether quantity denotes paid units or received units before selecting the coupon formula.
```hint Separate units from money
First determine how many of the received units are chargeable. Then multiply by an exact integer price and format the final cents.
```
Overview: Calculate exact-cent inventory totals with stock checks and a clearly defined buy-X-get-Y-free coupon, including partial groups and two-decimal output.
Read the full Instacart Software Engineer interview experience this question came from
Compute the total price of a requested quantity of one inventory item, then support an optional buy-X-get-Y-free coupon for that item.
Implement `purchase_total(inventory: string[][], item: string, quantity: int, buy: int, free: int) -> string`.
### Constraints & Assumptions
These coupon and error semantics are explicit practice choices where the report is incomplete. Quantity is the total number of units the customer receives, including any free units. For each complete group of `buy + free` units, charge for `buy`; any remaining units are charged up to `buy`. Thus with buy 5/get 2, quantities 3, 6, and 7 pay for 3, 5, and 5 units respectively. No free units are added beyond the requested quantity.
- Each inventory row is `[name,stock,unitPrice]`; names are unique nonempty ASCII identifiers. Stock is a nonnegative integer string. Unit price is a nonnegative decimal string with exactly two digits after the point.
- At most 1000 inventory rows, stock and quantity at most 1000000, and unit price at most `1000000.00`. Quantity is nonnegative.
- `buy == 0` and `free == 0` means no coupon. Otherwise `1 <= buy <= 1000000` and `0 <= free <= 1000000`.
- Return `UNKNOWN_ITEM` if the item does not exist. Otherwise return `OUT_OF_STOCK` if quantity exceeds stock. No inventory mutation occurs.
- On success return the total with exactly two fractional digits and no currency symbol. Parse and calculate using integer cents, not binary floating point.
### Examples
```text
inventory = [["A","50","0.25"],["B","10","1.50"]]
item = "A", quantity = 7, buy = 5, free = 2
result = "1.25"
```
For the same item, quantity 3 costs `0.75`; quantity 0 costs `0.00`; quantity 51 returns `OUT_OF_STOCK`. Without a coupon, seven units cost `1.75`.
Explain how the function avoids decimal rounding errors and why an incomplete qualifying purchase cannot receive the full advertised free quantity. In an interview, clarify whether quantity denotes paid units or received units before selecting the coupon formula.
```hint Separate units from money
First determine how many of the received units are chargeable. Then multiply by an exact integer price and format the final cents.
```
Constraints
- At most 1000 inventory rows [name, stock, unitPrice]; names are unique nonempty ASCII identifiers.
- Stock and quantity are nonnegative integers at most 1000000; stock is provided as an integer string.
- Unit price is nonnegative, at most 1000000.00, and has exactly two fractional digits.
- Both buy and free are zero for no coupon; otherwise 1 <= buy <= 1000000 and 0 <= free <= 1000000.
- Quantity is total received units. A full buy+free group charges buy units; its remainder charges at most buy.
- Return UNKNOWN_ITEM for absent names, otherwise OUT_OF_STOCK if quantity exceeds stock. Success is an exact two-decimal string. Do not mutate inventory.
Examples
Input: ([['A', '50', '0.25'], ['B', '10', '1.50']], 'A', 7, 5, 2)
Expected Output: '1.25'
Explanation: One full group charges five units.
Input: ([['A', '50', '0.25']], 'A', 6, 5, 2)
Expected Output: '1.25'
Explanation: An incomplete group includes one requested free unit after five paid units.