Design Vending Machine With Exact Payment
Design a vending machine that stores packaged products and dispenses one selected product after the customer inserts its exact price.
The machine does not return change. It does not maintain a cash inventory. If an inserted denomination would make the total greater than the selected product's price, that denomination is rejected.
Class Definition
VendingMachine(List<String> products, List<Integer> acceptedDenominations)
- Each product record has the format
"productCode,name,price,quantity,capacity".
acceptedDenominations contains the cash denominations accepted by the machine.
- Prices and denominations are represented in the smallest currency unit, such as paise or cents.
Method Signatures
View Products
List<String> getProducts()
- Returns every product in the format
"productCode,name,price,quantity".
- Products are returned in ascending lexicographical order of product code.
- Out-of-stock products are included with quantity
0.
Select a Product
String selectProduct(String productCode)
- Returns
"SELECTED,productCode,price" when an available product is selected.
- Returns
"INVALID_PRODUCT" when the product code does not exist.
- Returns
"OUT_OF_STOCK" when the product has no available units.
- Returns
"TRANSACTION_IN_PROGRESS" when another product is already selected.
Insert Cash
String insertCash(int denomination)
- Adds one cash unit of the specified denomination to the current transaction.
- Returns
"ACCEPTED,totalInserted" when the cash is accepted.
- Returns
"NO_PRODUCT_SELECTED" when no product is selected.
- Returns
"UNSUPPORTED_DENOMINATION" when the denomination is not accepted by the machine.
- Returns
"EXCEEDS_PRICE" when accepting the denomination would make the inserted total greater than the product price.
- A rejected denomination is not added to the transaction.
Complete a Purchase
String completePurchase()
- Dispenses the selected product only when the inserted total exactly equals its price.
- Returns
"DISPENSED,productCode" when the purchase succeeds.
- Returns
"INSUFFICIENT_PAYMENT,remainingAmount" when more cash is required. The transaction remains active.
- Returns
"NO_ACTIVE_TRANSACTION" when no product is selected.
Cancel a Transaction
List<Integer> cancelTransaction()
- Cancels the current transaction before the product is dispensed.
- Returns the exact denominations inserted by the customer in insertion order.
- Returns an empty list when no cash was inserted or no transaction exists.
- The selected product and inserted total are cleared after cancellation.
Restock a Product
boolean restockProduct(String productCode, int quantity, int newPrice)
- Adds
quantity units to an existing product slot and changes its price to newPrice.
- Returns
true when both the quantity and price are updated.
- Returns
false if the product does not exist, a parameter is invalid, the capacity would be exceeded or a customer transaction is active.
- The operation is atomic. If it fails, neither the quantity nor the price is changed.
Transaction Rules
- The machine handles one customer transaction at a time.
- Each successful transaction dispenses exactly one product.
- The customer must insert the exact product price.
- The machine never returns change.
- An insertion that would exceed the product price is immediately rejected.
- An insufficient-payment result does not clear the selected product or previously inserted cash.
- Cancelling returns the exact cash units inserted during the transaction.
- After a successful purchase or cancellation, the machine becomes ready for another transaction.
- Restocking is not allowed while a customer transaction is active.
Constraints
1 ≤ products.size() ≤ 1,000
1 ≤ acceptedDenominations.size() ≤ 100
- Every product record contains exactly five comma-separated fields.
- Product codes are unique, non-empty and contain at most
20 letters or digits.
- Product names contain at most
100 characters and do not contain commas.
1 ≤ price, newPrice ≤ 1,000,000,000
0 ≤ product quantity ≤ capacity ≤ 1,000,000
- Accepted denominations are unique positive integers.
1 ≤ denomination ≤ 1,000,000,000
- Every product price can be formed using one or more accepted denominations.
- For
restockProduct, 1 ≤ quantity ≤ 1,000,000.
- Parameter values are never null.
Examples
Example 1: Exact Payment
VendingMachine(products = ["A1,Orange Juice,65,2,5", "B4,Granola Bar,40,1,4"], acceptedDenominations = [5, 10, 20, 50]) selectProduct(productCode = "A1") Output: "SELECTED,A1,65" insertCash(denomination = 50) Output: "ACCEPTED,50" insertCash(denomination = 10) Output: "ACCEPTED,60" insertCash(denomination = 5) Output: "ACCEPTED,65" completePurchase() Output: "DISPENSED,A1"
The inserted total exactly equals the product price, so one unit is dispensed.
Example 2: Insufficient Payment
VendingMachine(products = ["D8,Trail Mix,75,2,6"], acceptedDenominations = [5, 10, 20, 50]) selectProduct(productCode = "D8") Output: "SELECTED,D8,75" insertCash(denomination = 50) Output: "ACCEPTED,50" completePurchase() Output: "INSUFFICIENT_PAYMENT,25" insertCash(denomination = 20) Output: "ACCEPTED,70" insertCash(denomination = 5) Output: "ACCEPTED,75" completePurchase() Output: "DISPENSED,D8"
The first completion attempt reports the missing amount. The transaction succeeds after the remaining amount is inserted.
Example 3: Insertion Exceeds the Price
VendingMachine(products = ["F2,Lemon Drink,60,3,5"], acceptedDenominations = [10, 20, 50]) selectProduct(productCode = "F2") Output: "SELECTED,F2,60" insertCash(denomination = 50) Output: "ACCEPTED,50" insertCash(denomination = 20) Output: "EXCEEDS_PRICE" insertCash(denomination = 10) Output: "ACCEPTED,60" completePurchase() Output: "DISPENSED,F2"
The denomination of 20 is rejected because it would make the total greater than 60.
Example 4: Cancel a Transaction
VendingMachine(products = ["M7,Baked Chips,90,3,5"], acceptedDenominations = [10, 20, 50, 100]) selectProduct(productCode = "M7") Output: "SELECTED,M7,90" insertCash(denomination = 20) Output: "ACCEPTED,20" insertCash(denomination = 50) Output: "ACCEPTED,70" cancelTransaction() Output: [20, 50]
Cancellation returns the exact cash denominations in insertion order.
Example 5: Restock and Change the Price
VendingMachine(products = ["P5,Sparkling Water,45,1,3"], acceptedDenominations = [5, 10, 20, 50]) restockProduct(productCode = "P5", quantity = 2, newPrice = 50) Output: true getProducts() Output: ["P5,Sparkling Water,50,3"] restockProduct(productCode = "P5", quantity = 1, newPrice = 55) Output: false getProducts() Output: ["P5,Sparkling Water,50,3"]
The first operation fills the slot and changes its price. The second fails because the slot is already full, so neither the quantity nor price changes.