Optimize Coupon Selection Under a Twenty-Point Budget
PalantirSoftware Engineer · Online AssessmentLast updated
Optimize coupon activations under a 20-point budget to maximize monetary savings while handling item/category stacking, savings caps, rounding, and tie-breaking.
Problem Statement
You are building a checkout discount engine for a grocery store. Shoppers have a loyalty point balance of up to 20 points and a collection of coupons they can activate. Each coupon costs a certain number of points to activate.
You are given:
- A list of
items, where each item has anid,category, andprice(in cents). - A list of
coupons, where each coupon has:id(unique string)level:"ITEM"(applies to a specific itemtarget_id) or"CATEGORY"(applies to all items intarget_category)discount_type:"PERCENT"or"FIXED"value: integer percent (1–100) or fixed amount in centsmax_savings: integer cap in cents on the total discount this coupon can provide across all items it touches (-1if uncapped)cost: integer point cost (1 <= cost <= 20)
budget: integer point budget (always20)
Discount & Stacking Rules
- At most one
ITEMcoupon and at most oneCATEGORYcoupon can apply to any single item. - When both apply to an item, the
ITEMcoupon applies first against the item's original price. TheCATEGORYcoupon then applies to the remaining balance of the item's price. - Percentage discounts round down to the nearest cent (
floor(price * value / 100)). - An item's price cannot be discounted below
0cents. - If a coupon has
max_savings != -1, the total discount provided by that coupon (summed across all applicable items) cannot exceedmax_savings. - Total point cost of all activated coupons cannot exceed
budget.
Optimization Objective & Tie-Breaking
Find the subset of coupons that maximizes total monetary savings in cents. If multiple subsets yield the same maximum savings:
- Choose the subset with the lower total point cost.
- If still tied, choose the subset whose sorted list of coupon IDs is lexicographically smaller.
Return a tuple/list: (max_savings_in_cents, points_used, list_of_activated_coupon_ids) with coupon IDs sorted alphabetically.
Interface
def optimize_coupons(
items: list[dict],
coupons: list[dict],
budget: int = 20
) -> tuple[int, int, list[str]]:
pass
Input Constraints
1 <= len(items) <= 501 <= len(coupons) <= 151 <= item["price"] <= 50000(cents)1 <= coupon["cost"] <= 20budget = 20
Examples
Example 1
items = [
{"id": "i1", "category": "dairy", "price": 1000}, # $10.00
{"id": "i2", "category": "dairy", "price": 500}, # $5.00
]
coupons = [
{"id": "c1", "level": "ITEM", "target": "i1", "discount_type": "FIXED", "value": 200, "max_savings": -1, "cost": 5},
{"id": "c2", "level": "CATEGORY", "target": "dairy", "discount_type": "PERCENT", "value": 20, "max_savings": 250, "cost": 10},
]
budget = 20
Output: (410, 15, ["c1", "c2"])
Explanation:
c1costs 5 points, saves 200 cents oni1.i1remaining price is 800 cents.c2costs 10 points (20% off dairy). Oni1, 20% of 800 = 160 cents. Oni2, 20% of 500 = 100 cents. Potential category savings = 260 cents, but capped atmax_savings = 250cents.- Total savings = 200 + 250 = 450 cents? Wait: without
c1,c2saves 20% of 1000 (200) + 20% of 500 (100) = 300 capped at 250. Withc1+c2,c1saves 200,c2saves min(250, 160 + 100) = 250. Total = 450 cents. Points used = 15. Output:(450, 15, ["c1", "c2"]).
Example 2
items = [{"id": "i1", "category": "bakery", "price": 400}]
coupons = [
{"id": "c_a", "level": "ITEM", "target": "i1", "discount_type": "PERCENT", "value": 50, "max_savings": -1, "cost": 10},
{"id": "c_b", "level": "ITEM", "target": "i1", "discount_type": "FIXED", "value": 200, "max_savings": -1, "cost": 10}
]
budget = 20
Output: (200, 10, ["c_a"])
Explanation: Both coupons save 200 cents and cost 10 points. Since only one item coupon can apply to i1, they cannot stack. Both achieve 200 cents savings at 10 points; "c_a" is chosen because ["c_a"] < ["c_b"] lexicographically.
Hints
Hint 1
Given len(coupons) <= 15, the total number of coupon subsets is at most 32,768, making power-set enumeration or branch-and-bound search feasible.
Hint 2
For any chosen subset of coupons, group coupons by target item and category to ensure at most one item coupon and at most one category coupon affect any given item.
Hint 3
Remember to apply coupon savings caps after evaluating all items affected by that specific coupon, not on a per-item basis.
Follow-up questions
- How would you optimize this if len(coupons) were up to 100, assuming coupons within different categories are completely independent?
- If multiple category coupons were allowed to stack on the same item, what dynamic programming formulation would find the optimal combination per item?
- How would you modify the system to handle order-level coupons (e.g., $10 off orders over $50) alongside item and category coupons?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.