Shopping Cart Checkout
Problem
Build a shopping cart. Prices are whole numbers (cents). Commands: ADD name price qty (add qty items; if the item is already in the cart, only the quantity grows), REMOVE name qty (print error if the cart has fewer than qty of that item; an item with quantity 0 leaves the cart), COUPON percent (set the discount percent, replacing the old one) and TOTAL. ADD, REMOVE and COUPON print ok (or error). TOTAL prints three numbers: the subtotal, the discount (subtotal * percent / 100, rounded down) and the total to pay.
Constraints
- 1 <= lines <= 1000
- 0 <= percent <= 100
Examples
Input
ADD pen 150 4 TOTAL COUPON 10 TOTAL
Output
ok 600 0 600 ok 600 60 540
Solutions
A Cart class keeps items and the coupon together and exposes the four operations. The price rule (round down the discount) lives in one method, so it is easy to change and to test.
/*
* Problem : Process lines.
* Input : Several command lines.
* Output : One result per command.
* Approach: Cart class.
* Time : O(n * items)
* Space : O(items)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// Step 1: The cart keeps its items and the coupon. The rules for the money are in one place.
static class Cart {
private final java.util.Map<String, long[]> items = new java.util.LinkedHashMap<String, long[]>();
private long percent = 0;
void add(String name, long price, long qty) {
long[] item = items.get(name);
if (item == null) {
items.put(name, new long[] {price, qty});
} else {
item[1] += qty;
}
}
boolean remove(String name, long qty) {
long[] item = items.get(name);
if (item == null || item[1] < qty) {
return false;
}
item[1] -= qty;
if (item[1] == 0) {
items.remove(name);
}
return true;
}
void coupon(long percent) {
this.percent = percent;
}
// Step 2: Subtotal, then discount rounded down, then total.
String total() {
long subtotal = 0;
for (long[] item : items.values()) {
subtotal += item[0] * item[1];
}
long discount = subtotal * percent / 100;
return subtotal + " " + discount + " " + (subtotal - discount);
}
}
// This method solves the task. It receives the input and returns the answer.
static String[] solve(String[] lines) {
Cart cart = new Cart();
String[] output = new String[lines.length];
for (int i = 0; i < lines.length; i++) {
String[] part = lines[i].split(" ");
if (part[0].equals("ADD")) {
cart.add(part[1], Long.parseLong(part[2]), Long.parseLong(part[3]));
output[i] = "ok";
} else if (part[0].equals("REMOVE")) {
output[i] = cart.remove(part[1], Long.parseLong(part[2])) ? "ok" : "error";
} else if (part[0].equals("COUPON")) {
cart.coupon(Long.parseLong(part[1]));
output[i] = "ok";
} else {
output[i] = cart.total();
}
}
return output;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
java.util.List<String> all = new java.util.ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
all.add(line);
}
}
String[] lines = all.toArray(new String[0]);
System.out.println(String.join("\n", solve(lines)));
}
}
Hints (2)
- Why keep money in whole cents?
- Where is the discount rounded?