1. Description
- Implement the RandomizedSet class:
- RandomizedSet() Initializes the RandomizedSet object.
- bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
- bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
- int getRandom() Returns a random element from the current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.
- You must implement the functions of the class such that each function works in average O(1) time complexity.
- Design a data structure that supports the following operations under the average time complexity O(1).
- insert(val): when the element val does not exist, insert the item into the collection.
- remove(val): removes the element val from the collection when it exists.
- getRandom: returns an item in an existing collection at random. Each element should have the same probability of being returned.
2. Analysis
First, think about what data structure can be inserted and deleted at O(1) - hash table, but the hash table encounters problems when getRandom, because getRandom needs to generate a random index and find elements according to this index, but the hash table does not have an index (for example, if you create a hash table of indexToValue type, you cannot delete it at constant time).
Therefore, in order to implement getRandom, you must use random access data structures. First, think of arrays. However, the problem with array storage is that the elements need to be moved during insertion and deletion. The time complexity is O(n). Here, the tail insertion and deletion can be used to solve the problem, so that the insertion and deletion only need O(1) time.
For the insert operation, insert at the end of the array, but for the delete operation, you need to find the element to be deleted within O(1), which requires a valToIndex hash table to store the element value and its subscript every time you insert a new element. When deleting, first find the corresponding subscript in the hash table, and then exchange the elements to the tail in the array for deletion, so as to realize O(1) time deletion. Note that the hash table needs to be updated in time after deleting elements.
3. Code
class RandomizedSet { List<Integer> nums; Map<Integer, Integer> valToIndex; Random rand = new Random(); /** Initialize your data structure here. */ public RandomizedSet() { // The bottom layer of ArrayList is dynamic array nums = new ArrayList<>(); valToIndex = new HashMap<>(); } /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ public boolean insert(int val) { if(valToIndex.containsKey(val)) return false; valToIndex.put(val, nums.size()); nums.add(nums.size(), val); return true; } /** Removes a value from the set. Returns true if the set contained the specified element. */ public boolean remove(int val) { if(!valToIndex.containsKey(val)) return false; // Find the corresponding subscript in the hash table int idx = valToIndex.get(val); int lastElement = nums.get(nums.size() - 1); // It is equivalent to deleting after exchanging with the last element nums.set(idx, lastElement); // Update hash table valToIndex.put(lastElement, idx); valToIndex.remove(val); nums.remove(nums.size() - 1); return true; } /** Get a random element from the set. */ public int getRandom() { return nums.get(rand.nextInt(nums.size())); } } /** * Your RandomizedSet object will be instantiated and called as such: * RandomizedSet obj = new RandomizedSet(); * boolean param_1 = obj.insert(val); * boolean param_2 = obj.remove(val); * int param_3 = obj.getRandom(); */
4. Summary
The design idea of data structure is to think about which known data structures can meet the requirements of characteristics, and the data structures can be combined when necessary.