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.
Example 1:
Input: ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
Output: [null, true, false, true, 2, true, false, 2]Explanation:
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomizedSet.remove(2); // Returns false as 2 does not exist in the set.
randomizedSet.insert(2); // Inserts 2 to the set, returns true. Set now contains [1,2].
randomizedSet.getRandom(); // getRandom() should return either 1 or 2 randomly.
randomizedSet.remove(1); // Removes 1 from the set, returns true. Set now contains [2].
randomizedSet.insert(2); // 2 was already in the set, so return false.
randomizedSet.getRandom(); // Since 2 is the only number in the set, getRandom() will always return 2.
Constraints:
-((2^31)-1) <= val <= ((2^31)-1)2,00,000 calls will be made to insert, remove, and getRandom.getRandom is called.Before attempting this problem, you should be comfortable with:
A hash map provides O(1) average time for insert and delete operations, making it a natural choice for the first two requirements. However, hash maps don't support random access by index.
For getRandom(), we need to pick a random element, but iterating to a random position takes O(n) time. We convert the keys to a list and pick a random index.
This approach sacrifices getRandom() performance to keep the implementation simple.
numMap and a size counter.val exists in the map, return false. Otherwise, add it to the map with any value and increment size. Return true.val doesn't exist in the map, return false. Otherwise, delete it from the map and decrement size. Return true.0 to size - 1. Convert the map's keys to a list and return the element at that index.class RandomizedSet:
def __init__(self):
self.numMap = {}
self.size = 0
def insert(self, val: int) -> bool:
if val in self.numMap:
return False
self.numMap[val] = 1
self.size += 1
return True
def remove(self, val: int) -> bool:
if val not in self.numMap:
return False
del self.numMap[val]
self.size -= 1
return True
def getRandom(self) -> int:
idx = random.randint(0, self.size - 1)
return list(self.numMap.keys())[idx]To achieve O(1) for all operations including getRandom(), we combine a hash map with a dynamic array. The array stores the actual values and allows random access, while the hash map stores each value's index in the array for fast lookups.
The tricky part is deletion: removing from the middle of an array is O(n). We solve this by swapping the element to delete with the last element, then removing from the end in O(1) time.
This swap-and-pop technique is a common pattern for O(1) deletion from unordered collections.
numMap (value to index) and a list nums.val exists in the map, return false. Otherwise, add val to the end of the list and store its index in the map. Return true.val doesn't exist, return false. Get the index of val, swap it with the last element in the list, update the swapped element's index in the map, remove the last element from the list, and delete val from the map. Return true.class RandomizedSet:
def __init__(self):
self.numMap = {}
self.nums = []
def insert(self, val: int) -> bool:
if val in self.numMap:
return False
self.numMap[val] = len(self.nums)
self.nums.append(val)
return True
def remove(self, val: int) -> bool:
if val not in self.numMap:
return False
idx = self.numMap[val]
last = self.nums[-1]
self.nums[idx] = last
self.numMap[last] = idx
self.nums.pop()
del self.numMap[val]
return True
def getRandom(self) -> int:
return random.choice(self.nums)During removal, when swapping the element to delete with the last element, a critical step is updating the last element's index in the hash map before removing anything. Forgetting numMap[last] = idx causes the hash map to have a stale index for the swapped element, leading to incorrect behavior on subsequent operations involving that value.
When the element to remove is already at the last position (i.e., idx == len(nums) - 1), the swap operation effectively swaps the element with itself. While this works correctly in most implementations, some code paths may have issues if they delete from the map before updating it. The order of operations matters: update the map first, then remove from both the list and map.
A common initial approach is to use only a hash map, which provides O(1) insert and delete but O(n) for getRandom() since hash maps do not support random index access. Converting keys to a list on each getRandom() call defeats the O(1) requirement. The combination of hash map plus array is essential, where the array enables O(1) random access and the hash map enables O(1) lookup for the swap-and-pop deletion technique.