Insert Delete GetRandom O(1) - Duplicates allowed (hard)
update Jan 26,2018 10:57
Design a data structure that supports all following operations in average O(1) time.
Note: 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.
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();
Basic Idea:
和之前不允许重复的版本不同,这里需要考虑更多的细节:
首先,对于map中存储的index,这次需要用一个set来存储一个元素所有的index,之所以用set而不是list,是为了在remove的时候更方便地删除index;
在remove的时候,如果当前list的最后一个元素和要删除的元素相同,则选择删除最后一个元素,否则在换位的时候,更新set中index的时候会出问题;
Java Code:
class RandomizedCollection { private Map<Integer, Set<Integer>> map = new HashMap<>(); private List<Integer> list = new ArrayList<>(); /** Initialize your data structure here. */ public RandomizedCollection() {} /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */ public boolean insert(int val) { Set<Integer> indexSet = map.get(val); if (indexSet != null) { // already contains list.add(val); indexSet.add(list.size() - 1); return false; } else { // not already contain indexSet = new HashSet<>(); list.add(val); indexSet.add(list.size() - 1); map.put(val, indexSet); return true; } } /** Removes a value from the collection. Returns true if the collection contained the specified element. */ public boolean remove(int val) { Set<Integer> indexSet = map.get(val); if (indexSet == null) return false; // 拿出一个indexset中的index,用最后一个元素替换,然后删除最后一个元素, 如果 // 删除之后 val 对应的元素全被被删掉,要将map中对应记录删除 int index = indexSet.iterator().next(); // 如果最后一个元素是val,选择删除最后一个元素 if (list.get(list.size() - 1) == val) { index = list.size() - 1; } if (index == list.size() - 1) { // 直接删除最后一个 list.remove(list.size() - 1); } else { // 用最后一个元素替换之后,删除最后一个元素 int theLast = list.get(list.size() - 1); Set<Integer> indexSetOfTheLast = map.get(theLast); list.set(index, theLast); // 替换list中index位置为最后一个元素 indexSetOfTheLast.remove(list.size() - 1); // 更新换过去元素的index indexSetOfTheLast.add(index); list.remove(list.size() - 1); // 删掉最后一个元素 } // 更新 val 对应的 index,如果全部删掉,则删去其在map中的记录 indexSet.remove(index); if (indexSet.isEmpty()) map.remove(val); return true; } /** Get a random element from the collection. */ public int getRandom() { int index = (int)(Math.random() * list.size()); return list.get(index); } }