Stack Item and Category Coupons with an Eighty-Percent Cap
Company: Palantir
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Online Assessment
Extend a cart-discount calculation to combine item-specific and category-wide coupons. Discounts stack multiplicatively, and the unrounded total discount on each item is capped at 80 percent of its original price.
### Function Contract
Implement `apply_stacked_discounts(items, discounts) -> dict`.
Each item contains `name` (string), `price` (nonnegative integer cents), and `category` (string). Each coupon contains `type` (`"item"` or `"category"`), `name` (the item name or category to match), and integer `percent_off`.
For backward-compatible item coupons, a coupon without `type` is treated as `"item"`. There is at most one item coupon per item name and one category coupon per category, counting these legacy coupons in the same uniqueness rule.
Return exactly the integer keys `subtotal`, `total_discount`, and `final_total`.
### Application and Rounding Rules
1. Apply the item coupon before the category coupon, using each percentage on the remaining unrounded price.
2. Never let unrounded cumulative savings exceed 80 percent of the original price. Partially apply a coupon if necessary to reach that cap.
3. After all matching coupons and the cap are applied, round that item's final discount amount to the nearest integer cent, with exact half-cent ties going to the even integer.
4. Sum the rounded per-item discounts. Return the original subtotal, that sum, and their difference.
Do not round intermediate remaining prices or intermediate savings. Use exact percentage arithmetic. The 80-percent cap is applied before final cent rounding; the rounded monetary saving can differ from the mathematical capped amount by at most half a cent.
### Constraints and Clarifications
- Each array has between `0` and `100000` entries.
- Names and categories are nonempty ASCII strings of at most 100 characters, matched exactly and case-sensitively.
- `0 <= price <= 1000000000` and `0 <= percent_off <= 100`.
- Repeated cart rows are separate items and each receives matching coupons.
- Unmatched coupons are ignored.
- Bounds, integral percentages, and exact half-even rounding are explicit practice conventions.
- Totals may exceed signed 32-bit range.
### Examples
```text
items = [{"name": "Milk", "price": 1000, "category": "Dairy"}]
discounts = [{"type": "item", "name": "Milk", "percent_off": 10},
{"type": "category", "name": "Dairy", "percent_off": 20}]
Output: {"subtotal": 1000, "total_discount": 280, "final_total": 720}
```
```text
items = [{"name": "A", "price": 101, "category": "C"}]
discounts = [{"type": "item", "name": "A", "percent_off": 80},
{"type": "category", "name": "C", "percent_off": 80}]
Output: {"subtotal": 101, "total_discount": 81, "final_total": 20}
```
The second item's unrounded savings are capped at `80.8` cents, then rounded once to `81`.
```hint Work from the remaining price
Two percentage discounts multiply their remaining-price factors. Adding the percentages would give the wrong saving before the cap is considered.
```
Overview: Apply multiplicative item and category discounts, cap unrounded savings at eighty percent, and round each final item discount once.
Extend a cart-discount calculation to combine item-specific and category-wide coupons. Discounts stack multiplicatively, and the unrounded total discount on each item is capped at 80 percent of its original price.
Each item contains name (string), price (nonnegative integer cents), and category (string). Each coupon contains type ("item" or "category"), name (the item name or category to match), and integer percent_off.
For backward-compatible item coupons, a coupon without type is treated as "item". There is at most one item coupon per item name and one category coupon per category, counting these legacy coupons in the same uniqueness rule.
Return exactly the integer keys subtotal, total_discount, and final_total.
Application and Rounding Rules
Apply the item coupon before the category coupon, using each percentage on the remaining unrounded price.
Never let unrounded cumulative savings exceed 80 percent of the original price. Partially apply a coupon if necessary to reach that cap.
After all matching coupons and the cap are applied, round that item's final discount amount to the nearest integer cent, with exact half-cent ties going to the even integer.
Sum the rounded per-item discounts. Return the original subtotal, that sum, and their difference.
Do not round intermediate remaining prices or intermediate savings. Use exact percentage arithmetic. The 80-percent cap is applied before final cent rounding; the rounded monetary saving can differ from the mathematical capped amount by at most half a cent.
Constraints and Clarifications
Each array has between
0
and
100000
entries.
Names and categories are nonempty ASCII strings of at most 100 characters, matched exactly and case-sensitively.