Counting Set Wrapper (Composition)

Problem

Build a set of integers that also counts how many add attempts were made (even for numbers that were already in the set). Use composition: your class holds a normal set inside and forwards calls to it. Commands: add X (one attempt), addall X Y Z... (one attempt for each number), size (print the number of different numbers), attempts (print the number of attempts).

Constraints

  • 1 <= commands <= 100

Examples

Input

add 5
add 5
size
attempts

Output

1
2

Solutions

Best approachTime O(n)Space O(n)

Composition keeps the counting in one small class. Because the class only forwards to the inner set, the count is right even if the inner set's own addAll calls add again.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Run the commands.
 * Input   : Command lines.
 * Output  : One line per answer.
 * Approach: Wrapper class
 * Time    : O(n)
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: The wrapper HAS a set inside. It does not extend the set, so its own counting cannot be counted twice.
        static class CountingSet {
            private final java.util.Set<Integer> inner = new java.util.HashSet<Integer>();
            private int attempts = 0;

            // Step 2: Every add is one attempt, whether or not the number is new.
            void add(int value) {
                attempts++;
                inner.add(value);
            }

            int size() {
                return inner.size();
            }

            int attempts() {
                return attempts;
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        CountingSet set = new CountingSet();
        java.util.List<String> out = new java.util.ArrayList<String>();
        for (String line : lines) {
            String[] part = line.split(" ");
            if (part[0].equals("add")) {
                set.add(Integer.parseInt(part[1]));
            } else if (part[0].equals("addall")) {
                for (int i = 1; i < part.length; i++) {
                    set.add(Integer.parseInt(part[i]));
                }
            } else if (part[0].equals("size")) {
                out.add(String.valueOf(set.size()));
            } else {
                out.add(String.valueOf(set.attempts()));
            }
        }
        return out.toArray(new String[0]);
    }

    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. Why is a wrapper safer than extending the set class?