Inventory Management

Problem

Manage a shop inventory. Commands: add ITEM N, remove ITEM N, check ITEM and report. add prints ok. remove prints ok, or error: not enough ITEM if the shop has fewer than N (then nothing changes). check prints ITEM and its count (0 for an unknown item). report prints all items with a count above 0 in alphabetical order as ITEM COUNT separated by comma and space, or empty.

Constraints

  • 1 <= lines <= 10^4

Examples

Input

add pen 10
remove pen 3
check pen
report

Output

ok
ok
pen 7
pen 7

Solutions

Best approachTime O(n log n)Space O(n)

Methods that can fail return a result (true or false here) instead of changing the state halfway. The stock stays valid after every command. A sorted map or a sorted key list gives a stable report.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process lines.
 * Input   : Several lines.
 * Output  : One answer per command.
 * Approach: An Inventory class.
 * Time    : O(n log n)
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: The Inventory keeps a count for every item name. The map is a TreeMap, so names stay sorted.
        static class Inventory {
            private final java.util.Map<String, Integer> stock = new java.util.TreeMap<>();

            void add(String item, int amount) {
                stock.merge(item, amount, Integer::sum);
            }

            // Step 2: Removing more than we have is an error. The stock must not change then.
            boolean remove(String item, int amount) {
                int have = stock.getOrDefault(item, 0);
                if (have < amount) {
                    return false;
                }
                stock.put(item, have - amount);
                return true;
            }

            int count(String item) {
                return stock.getOrDefault(item, 0);
            }

            // Step 3: The report lists the items with a count above zero, as "name count" separated by comma and space.
            String report() {
                java.util.List<String> parts = new java.util.ArrayList<>();
                for (java.util.Map.Entry<String, Integer> entry : stock.entrySet()) {
                    if (entry.getValue() > 0) {
                        parts.add(entry.getKey() + " " + entry.getValue());
                    }
                }
                return parts.isEmpty() ? "empty" : String.join(", ", parts);
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        Inventory inventory = new Inventory();
        String[] output = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            String[] part = lines[i].split(" ");

            // Step 4: Run the command and make one output line.
            if (part[0].equals("add")) {
                inventory.add(part[1], Integer.parseInt(part[2]));
                output[i] = "ok";
            } else if (part[0].equals("remove")) {
                output[i] = inventory.remove(part[1], Integer.parseInt(part[2])) ? "ok" : "error: not enough " + part[1];
            } else if (part[0].equals("check")) {
                output[i] = part[1] + " " + inventory.count(part[1]);
            } else {
                output[i] = inventory.report();
            }
        }
        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 (1)
  1. What must be true about the stock after a failed remove?