Multiset with Counts

medium Java Collections

Problem

A multiset can hold the same item many times. Every line is a command: ADD item, REMOVE item (remove one copy), COUNT item, DISTINCT (how many different items are inside) or TOTAL (how many copies are inside altogether). ADD prints ok. REMOVE prints ok or none when the item is not inside. Other commands print a number.

Constraints

  • 1 <= lines <= 5000
  • items are words without spaces

Examples

Input

ADD a
ADD a
COUNT a
REMOVE a
COUNT a
TOTAL

Output

ok
ok
2
ok
1
1

Solutions

Best approachTime O(n)Space O(n)

Counts in a map make every command O(1). Removing the item when its count reaches zero keeps DISTINCT equal to the map size.

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

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        // Step 1: A map from item to its number of copies. An item with 0 copies is removed from the map, so DISTINCT is the map size.
        java.util.Map<String, Integer> counts = new java.util.HashMap<String, Integer>();
        long total = 0;
        String[] output = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            String[] part = lines[i].split(" ");
            if (part[0].equals("ADD")) {
                counts.merge(part[1], 1, Integer::sum);
                total++;
                output[i] = "ok";
            } else if (part[0].equals("REMOVE")) {
                Integer have = counts.get(part[1]);
                if (have == null) {
                    output[i] = "none";
                } else {
                    // Step 2: Take one copy. Drop the item when the last copy is gone.
                    if (have == 1) {
                        counts.remove(part[1]);
                    } else {
                        counts.put(part[1], have - 1);
                    }
                    total--;
                    output[i] = "ok";
                }
            } else if (part[0].equals("COUNT")) {
                output[i] = String.valueOf(counts.getOrDefault(part[1], 0));
            } else if (part[0].equals("DISTINCT")) {
                output[i] = String.valueOf(counts.size());
            } else {
                output[i] = String.valueOf(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)
  1. Why delete the key at zero copies?
  2. Which commands change the total?