PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep
|Home/Coding & Algorithms/CloudKitchens

Design receipt system with combo discounts

Last updated: Jun 15, 2026

Quick Overview

A CloudKitchens software-engineer technical screen: build a point-of-sale order that prints an itemized receipt on every item tap, then extend it to apply combo discounts. It tests cart data-structure design, receipt formatting, and the algorithm for selecting a valid set of non-overlapping combos.

  • Medium
  • CloudKitchens
  • Coding & Algorithms
  • Software Engineer

Design receipt system with combo discounts

Company: CloudKitchens

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

##### Question You are building a point-of-sale ordering UI for a food-ordering workflow. You are given class stubs and a callback you must wire up: - `Item(id, name, price)` - `Menu` with `lookupById(itemId)` - `Order` with `add`, `remove`, and per-item `quantities` - `Display` with `show(receipt)` - `onUserUpdateSelected(itemId)` — called by the framework each time the user taps an item **Part A — Incremental receipt.** Each time `onUserUpdateSelected(itemId)` is called, add the item to the current `Order`, update its quantity, and print a receipt string via `Display.show(receipt)`. The receipt must: 1. List each line in the form `"<name> x <qty> @ <unitPrice> = <lineTotal>"`. 2. Print a subtotal and a grand total. It must work correctly for repeated additions of the same item (quantities aggregate) and for multiple distinct items. Implement the data structures and the `toString`/formatting methods needed to support this. **Part B — Combo discounts.** Extend the system to support combo discounts. A `Combo` is defined by: - a required count `k` (number of qualifying items needed to form one combo), - the set of eligible item IDs (or categories) that can satisfy it, and - a discount value with a type, either `amountOff` (flat amount) or `percentOff`. (In the simplest form a combo is just `k items -> discountAmount`.) After each item addition, find **any valid set of non-overlapping combos** that can be applied to the current `Order`, apply the resulting discount(s), and reprint the updated receipt showing which combos were applied and the final discounted total. You do **not** need to maximize the total discount or the number of combos — returning any valid application is sufficient. In your answer, describe your data model for items, the cart/order, and combos; give pseudocode or code for `onUserUpdateSelected`; explain the algorithm you use to pick a valid set of non-overlapping combos (e.g., greedy with a backtracking fallback that guarantees a valid set if one exists); analyze the time and space complexity; and state your assumptions (e.g., unique item IDs, integer quantities, rounding rule for percentage discounts).

Quick Answer: A CloudKitchens software-engineer technical screen: build a point-of-sale order that prints an itemized receipt on every item tap, then extend it to apply combo discounts. It tests cart data-structure design, receipt formatting, and the algorithm for selecting a valid set of non-overlapping combos.

Solution

### Data model ``` Item { id: int, name: string, price: int } // price in cents to avoid float rounding Menu { lookupById(id) -> Item } Order { counts: Map<itemId, qty> } // single source of truth for the cart Combo { id, k: int, eligibleItemIds: Set<int>, discountType: AMOUNT_OFF|PERCENT_OFF, value: int } Display { show(receipt: string) } ``` Keep the cart as a `Map<itemId, qty>` (a hash map). This makes Part A O(1) per add and lets the receipt aggregate repeated items naturally. Store prices as integer cents so totals and percentage discounts round deterministically. ### Part A — incremental receipt ``` onUserUpdateSelected(itemId): order.counts[itemId] += 1 # add / increment quantity receipt = renderReceipt(order) # includes discounts once Part B is wired in display.show(receipt) renderReceipt(order): lines = [] subtotal = 0 for (itemId, qty) in order.counts (in a stable order, e.g. insertion or by id): item = menu.lookupById(itemId) lineTotal = item.price * qty subtotal += lineTotal lines.append(format("%s x %d @ %s = %s", item.name, qty, money(item.price), money(lineTotal))) (discountLines, discountTotal) = applyCombos(order) # Part B; [] and 0 before Part B lines += discountLines grandTotal = subtotal - discountTotal return join(lines, "\n") + "\nSubtotal: " + money(subtotal) + (discountTotal ? "\nDiscounts: -" + money(discountTotal) : "") + "\nTotal: " + money(grandTotal) ``` `toString`/formatting lives in a single `renderReceipt` (or `Item.toReceiptLine`) helper so the line format `"<name> x <qty> @ <unitPrice> = <lineTotal>"` is defined in one place. Iterate the map in a stable order (insertion order or sorted by id) so the receipt is deterministic across reprints. ### Part B — selecting a valid set of non-overlapping combos "Non-overlapping" means each physical unit of an item can count toward at most one combo. The cleanest model is: each combo consumes `k` units drawn from a pool that is the union of its eligible items' remaining quantities. We only need *a* valid set, not the optimal one, so a greedy pass with a backtracking fallback is enough. **Greedy (fast path):** ``` applyCombos(order): remaining = copy(order.counts) # mutable working copy of quantities applied = [] discountTotal = 0 progress = true while progress: progress = false for combo in combos: avail = sum(remaining[id] for id in combo.eligibleItemIds) if avail >= combo.k: consume k units from remaining across eligible items (any order) base = price of the consumed units (for percentOff) d = (combo.discountType == AMOUNT_OFF) ? combo.value : round(base * combo.value / 100) discountTotal += d applied.append(combo) progress = true return (formatComboLines(applied), discountTotal) ``` Greedy alone can over-commit a shared item to the wrong combo when combos have overlapping eligible sets and tight inventory. Because the prompt only requires *any* valid set, the safe, general solution is **backtracking** that treats the choice of which combo to fill next (and which units it consumes) as a search, returning the first complete, conflict-free assignment: ``` search(remaining, appliedSoFar): if no combo can still be formed from remaining: return appliedSoFar # any reachable set is valid for combo c that can be formed: for each way to pick k eligible units from remaining (or just one canonical pick): remaining' = remaining - those units result = search(remaining', appliedSoFar + [c]) if result is acceptable: return result # accept first valid set # also allow NOT forming c, to explore alternatives return appliedSoFar ``` In practice: run the greedy pass first; if it forms at least one combo, take it. Keep backtracking only as a fallback for the corner case where greedy stalls but a valid combo set still exists (overlapping eligibility + scarce units). Re-run `applyCombos` after every `onUserUpdateSelected` so the discount reflects the current cart. ### Assumptions - Item IDs are unique; quantities are positive integers. - Prices stored as integer cents; `percentOff` rounds with a fixed rule (e.g. round-half-up) to avoid floating-point drift. - A unit may belong to at most one combo (non-overlapping). - No requirement to maximize discount — first valid assignment wins. ### Complexity - **Part A:** O(1) amortized to add an item; O(n) to render the receipt where n = number of distinct items in the cart. - **Part B greedy:** each outer pass is O(C · A) where C = number of combos and A = average eligible-pool scan; it runs until no progress, bounded by total units / min(k). Overall roughly O(U · C) where U = total units in the cart. - **Part B backtracking fallback:** worst case exponential in the number of combos/units, but it only triggers in the rare overlapping-scarcity corner case and is bounded by the small cart sizes typical of a single order. - **Space:** O(n) for the cart map plus O(C) for combos and O(depth) for the backtracking recursion stack.

Explanation

The interviewer is looking for: (1) a clean cart abstraction (a quantity map) that makes repeated-item aggregation and O(1) updates trivial; (2) receipt formatting isolated in one render/toString path that is re-invoked on every update; and (3) recognition that combo selection is a constraint-satisfaction / set-packing problem where, because only a *valid* (not optimal) set is required, greedy-with-backtracking-fallback is the right altitude. Strong candidates use integer cents to dodge rounding bugs, state explicit assumptions, and correctly analyze that the easy parts are linear while the combo search is the only place exponential blowup can hide.

Related Interview Questions

  • Implement menu parser and serializer - CloudKitchens (medium)
  • Design a menu manager with enums - CloudKitchens (Medium)
  • Design an in-memory cloud storage system - CloudKitchens (Medium)
  • Implement concurrent order-accept/pickup simulator - CloudKitchens (medium)
  • Answer static and streaming Top-K queries - CloudKitchens (medium)
CloudKitchens logo
CloudKitchens
Sep 6, 2025, 12:00 AM
Software Engineer
Technical Screen
Coding & Algorithms
7
0
Question

You are building a point-of-sale ordering UI for a food-ordering workflow. You are given class stubs and a callback you must wire up:

  • Item(id, name, price)
  • Menu with lookupById(itemId)
  • Order with add , remove , and per-item quantities
  • Display with show(receipt)
  • onUserUpdateSelected(itemId) — called by the framework each time the user taps an item

Part A — Incremental receipt. Each time onUserUpdateSelected(itemId) is called, add the item to the current Order, update its quantity, and print a receipt string via Display.show(receipt). The receipt must:

  1. List each line in the form "<name> x <qty> @ <unitPrice> = <lineTotal>" .
  2. Print a subtotal and a grand total.

It must work correctly for repeated additions of the same item (quantities aggregate) and for multiple distinct items. Implement the data structures and the toString/formatting methods needed to support this.

Part B — Combo discounts. Extend the system to support combo discounts. A Combo is defined by:

  • a required count k (number of qualifying items needed to form one combo),
  • the set of eligible item IDs (or categories) that can satisfy it, and
  • a discount value with a type, either amountOff (flat amount) or percentOff .

(In the simplest form a combo is just k items -> discountAmount.) After each item addition, find any valid set of non-overlapping combos that can be applied to the current Order, apply the resulting discount(s), and reprint the updated receipt showing which combos were applied and the final discounted total. You do not need to maximize the total discount or the number of combos — returning any valid application is sufficient.

In your answer, describe your data model for items, the cart/order, and combos; give pseudocode or code for onUserUpdateSelected; explain the algorithm you use to pick a valid set of non-overlapping combos (e.g., greedy with a backtracking fallback that guarantees a valid set if one exists); analyze the time and space complexity; and state your assumptions (e.g., unique item IDs, integer quantities, rounding rule for percentage discounts).

Solution

Show

Submit Your Answer to Earn 20XP

Sign in to leave a comment

Loading comments...

Browse More Questions

More Coding & Algorithms•More CloudKitchens•More Software Engineer•CloudKitchens Software Engineer•CloudKitchens Coding & Algorithms•Software Engineer Coding & Algorithms
PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.