335. Design Vending Machine With Exact Payment
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.


Please use Laptop/Desktop or any other large screen to add/edit code.