LeetCode-in-Java

381. Insert Delete GetRandom O(1) - Duplicates allowed

Hard

RandomizedCollection is a data structure that contains a collection of numbers, possibly duplicates (i.e., a multiset). It should support inserting and removing specific elements and also removing a random element.

Implement the RandomizedCollection class:

You must implement the functions of the class such that each function works on average O(1) time complexity.

Note: The test cases are generated such that getRandom will only be called if there is at least one item in the RandomizedCollection.

Example 1:

Input

["RandomizedCollection", "insert", "insert", "insert", "getRandom", "remove", "getRandom"]
[[], [1], [1], [2], [], [1], []]

Output: [null, true, false, true, 2, true, 1]

Explanation:

RandomizedCollection randomizedCollection = new RandomizedCollection(); 
randomizedCollection.insert(1);     // return true since the collection does not contain 1. 
                                    // Inserts 1 into the collection. 
randomizedCollection.insert(1);     // return false since the collection contains 1. 
                                    // Inserts another 1 into the collection. Collection now contains [1,1]. 
randomizedCollection.insert(2);     // return true since the collection does not contain 2. 
                                    // Inserts 2 into the collection. Collection now contains [1,1,2]. 
randomizedCollection.getRandom();   // getRandom should: 
                                    // - return 1 with probability 2/3, or 
                                    // - return 2 with probability 1/3. 
randomizedCollection.remove(1);     // return true since the collection contains 1. 
                                    // Removes 1 from the collection. Collection now contains [1,2]. 
randomizedCollection.getRandom();   // getRandom should return 1 or 2, both equally likely.

Constraints:

Solution

import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;

@SuppressWarnings({"java:S3824", "java:S2245"})
public class RandomizedCollection {
    private HashMap<Integer, HashSet<Integer>> hashMap;
    private int[] arr;
    private int size;
    private Random rand;

    public RandomizedCollection() {
        hashMap = new HashMap<>();
        size = 0;
        arr = new int[200000];
        rand = new Random();
    }

    public boolean insert(int val) {
        boolean exists = true;
        if (!hashMap.containsKey(val)) {
            exists = false;
            hashMap.put(val, new HashSet<>());
        }
        hashMap.get(val).add(size);
        arr[size] = val;
        size++;
        return !exists;
    }

    public boolean remove(int val) {
        if (!hashMap.containsKey(val)) {
            return false;
        }
        int idx = hashMap.get(val).iterator().next();
        int lastVal = arr[size - 1];
        if (lastVal != val) {
            hashMap.get(lastVal).add(idx);
            hashMap.get(val).remove(idx);
        }
        hashMap.get(lastVal).remove(size - 1);
        arr[idx] = lastVal;
        if (hashMap.get(val).isEmpty()) {
            hashMap.remove(val);
        }
        size--;
        return true;
    }

    public int getRandom() {
        int idx = rand.nextInt(size);
        return arr[idx];
    }
}

/*
 * Your RandomizedCollection object will be instantiated and called as such:
 * RandomizedCollection obj = new RandomizedCollection();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */