Insert Delete GetRandom O(1) - Duplicates allowed
Design a data structure that supports all following operations in average O(1) time.
Example
// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();
// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);
// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);
// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);
// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();
// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);
// getRandom should return 1 and 2 both equally likely.
collection.getRandom();
Notice
Duplicate elements are allowed.
insert(val): Inserts an item val to the collection.
remove(val): Removes an item val from the collection if present.
getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.
解法
思路1
- 在I的基础上允许duplicate
- 还是用的I的思想
- 这种题不在乎时间复杂度的其实非常简单,要求O(1)的话,需要对数据结构做一些改变
- 在I的基础上直接做,那么久需要维护一个val -> list of values, 如果只是一个val -> 次数,那么无法找到对应的list中的位置,无法在O(1)进行getRandom
- 最开始想使用HashMap
- 这样能通过value找到了这个value对应的index list,但是使用List又需要O(k)时间遍历,
- 所以想到了HashMap> 
- value -> a map(list) of nodes, in the map, index -> value
- 这样我们可以通过O(1)完成对这个双重map的操作
- 每次remove的时候都会对这个双重map进行操作,而且都是O(1)
思路2
- 其实跟思路1差不多
- 变成linkedlist with HashMap 或者 linkedHashMap
- 有head和tail节点进行删除,增加
- 代码
class RandomizedCollection {
    /** Initialize your data structure here. */
    // value -> a map(list) of nodes, in the map, index -> value
    Map<Integer, Map<Integer, Integer>> value_map;
    Map<Integer, Integer> index_map;
    List<Integer> list;
    Random rand;
    public RandomizedCollection() {
        value_map = new HashMap<Integer, Map<Integer, Integer>>();
        index_map = new HashMap<Integer, Integer>();
        list = new ArrayList<Integer>();
        rand = new Random();
    }
    /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
    public boolean insert(int val) {
        // write your code here
        Map<Integer, Integer> map = null;
        if (value_map.containsKey(val)) {
            map = value_map.get(val);
        } else {
            map = new HashMap<Integer, Integer>();
        }
        list.add(val);
        map.put(list.size() - 1, val);
        value_map.put(val, map);
        index_map.put(list.size() - 1, val);
        return true;
    }
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    public boolean remove(int val) {
        // write your code here
        if (!value_map.containsKey(val)) {
            return false;
        }
        Map<Integer, Integer> map = value_map.get(val);
        if (map.size() == 0) {
            return false;
        }
        Iterator iterator = map.entrySet().iterator();
        Map.Entry pair = (Map.Entry)iterator.next();
        int index = (Integer)pair.getKey();
        map.remove(index);
        index_map.remove(index);
        int last_value = list.get(list.size() - 1);
        if (last_value == val) {
            list.remove(list.size() - 1);
            return true;
        }
        int last_index = list.size() - 1;
        swap(list, index, last_index);
        list.remove(list.size() - 1);
        index_map.remove(last_index);
        index_map.put(index, last_value);
        Map<Integer, Integer> map_of_last = value_map.get(last_value);
        map_of_last.remove(last_index);
        map_of_last.put(index, last_value);
        return true;
    }
    public void swap(List<Integer> list, int index1, int index2) {
        int temp = list.get(index1);
        list.set(index1, list.get(index2));
        list.set(index2, temp);
    }
    /** Get a random element from the collection. */
    public int getRandom() {
        // write your code here
        return list.get(rand.nextInt(list.size()));
    }
}
/**
 * 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();
 */