Insert Delete GetRandom O(1)
Design a set with average O(1) insertion, removal, and uniform random selection.
Open on LeetCode ↗Intuition
A hash set gives constant-time membership and removal, but it cannot choose a uniformly random stored value by index. An array gives constant-time random indexing, yet deleting from its middle normally shifts later elements. Keep both structures synchronized: the map tells you where a value sits in the array, and removal fills the hole with the array's last value before popping the end. That swap changes only one stored index, so both deletion and random access remain O(1).
Constant-time membership and deletion suggest hashing, while uniform random selection suggests a dense indexable array. When both are required, store value-to-index mappings and use swap-delete to prevent gaps and shifts.
Approach
Pair a dense value array with an index map
Store every value once in values, and map that value to its current array index. Insertion checks the map, records the next array position, and appends. The array stays dense, which is necessary for every index to have equal probability in getRandom.
Delete by moving the final value into the hole
Use the map to find the removed value's index. Copy the final array value into that index, update the moved value's map entry, then pop the array tail and delete the removed key. This also works when the removed value is already last: the temporary self-update is harmless before its key is deleted.
Sample directly from the dense array
Choose a random array element rather than a random map key. Because every stored value occupies exactly one array position, uniform random indexing gives every value equal probability. Each public operation is O(1) on average.
Solution
Common pitfalls
Using linear array removal
self.values.remove(val)
self.values[index] = last_value
list.remove searches and shifts elements, violating the average O(1) requirement.
Leaving the moved value's old index
self.index[last_value] = len(self.values) - 1
self.index[last_value] = index
After the swap, the last value occupies the removed value's former slot. Keeping its tail index corrupts the next removal.
Sampling the map instead of the array
return random.choice(self.index)
return random.choice(self.values)
The array is the dense random-access structure; random.choice does not operate on a dictionary as a value sequence.
Edge cases
The value is copied onto its own index, popped, and removed from the map, leaving both structures empty.
The map check returns false before either structure changes, so no duplicate array slot is created.
The method returns false immediately and leaves the array-map invariant untouched.