AlgoMaster Logo

Insert Delete GetRandom O(1)

mediumFrequency7 min readUpdated June 23, 2026

Understanding the Problem

We need to design a data structure that supports three operations, all in average O(1) time: inserting an element, removing an element, and returning a uniformly random element.

No single standard data structure handles all three operations well. A hash set gives O(1) insert and remove, but it offers no way to pick a random element in O(1) because you cannot index into it. An array gives O(1) random access (pick a random index), but removing an arbitrary element is O(n) because you would need to shift the elements after it.

Combining both data structures solves this: an array for O(1) random access and a hash map for O(1) value-to-position lookups. To make removal O(1), swap the element being deleted with the last element of the array, then pop the last element. Both steps are constant time, and order does not matter for a set.

Key Constraints:

  • At most 2 * 10^5 calls → Each operation must be O(1) on average. A linear scan per call would be O(n) per call and time out at this volume.
  • -2^31 <= val <= 2^31 - 1 → Values span the full signed 32-bit range, so a fixed-size boolean array indexed by value is not viable. Membership has to go through a hash map.
  • At least one element when getRandom is called → getRandom never has to handle an empty set.

Approach 1: Hash Set with Linear Scan for Random

Intuition

A hash set handles membership checks, insertion, and deletion in O(1), so it covers insert and remove directly. The problem is getRandom: a hash set has no notion of position, so the only way to pick a random element is to copy all elements into a list and index into it.

That copy costs O(n) on every getRandom call, which breaks the O(1) requirement. The approach is correct but slow, and it isolates the exact bottleneck the optimal solution has to remove.

Algorithm

  1. Maintain a hash set to store all current elements.
  2. For insert(val): check if val is in the set. If not, add it and return true. Otherwise return false.
  3. For remove(val): check if val is in the set. If so, remove it and return true. Otherwise return false.
  4. For getRandom(): convert the set to a list (or array), generate a random index, and return the element at that index.

Example Walkthrough

Input:

0
RandomizedSet
1
insert
2
remove
3
insert
4
getRandom
5
remove
6
insert
7
getRandom
operations

Tracing the operations against a hash set: insert(1) adds 1, set becomes {1}, returns true. remove(2) finds nothing, returns false. insert(2) adds 2, set becomes {1, 2}, returns true. The first getRandom() copies {1, 2} into [1, 2] and returns 1 or 2. remove(1) removes 1, set becomes {2}, returns true. insert(2) finds 2 already present, returns false. The last getRandom() copies {2} into [2] and returns 2. Every getRandom rebuilds the array from scratch, which is the O(n) cost we want to eliminate.

0
-
1
true
2
false
3
true
4
2
5
true
6
false
7
2
result

Code

The bottleneck is getRandom rebuilding the array on every call. The next approach keeps a persistent array alongside the hash map, so random access by index is always available in O(1) without any copying.

Approach 2: Array + Hash Map (Optimal)

Intuition

Use the two data structures together, each covering the other's weakness. The array provides O(1) random access: generate a random index and return the element there. The hash map provides O(1) value-to-index lookup: given a value, find where it sits in the array without scanning.

Insert appends the new element to the end of the array and records its index in the hash map. getRandom picks a random index from 0 to size-1 and returns the array element there.

Removal is the operation that needs care. Deleting from the middle of an array normally costs O(n) because every later element shifts down by one. A set has no required order, so instead of shifting, move the last array element into the slot being vacated, update its index in the hash map, then pop the last element. The swap is one assignment, the pop is O(1), and the map sees one update and one deletion.

Algorithm

  1. Maintain an array list that stores all current elements, and a hash map valToIndex that maps each value to its index in the array.
  2. For insert(val): if val is already in the map, return false. Otherwise, append val to the end of the array, record its index in the map, and return true.
  3. For remove(val): if val is not in the map, return false. Otherwise, get val's index from the map. Swap the element at that index with the last element in the array. Update the map for the swapped element's new index. Remove the last element from the array and remove val from the map. Return true.
  4. For getRandom(): generate a random index between 0 and size-1 (inclusive) and return the array element at that index.

Example Walkthrough

1Initial state: list is empty, map is empty
1/9
1Initial state: map is empty
1/9

Code

Handling duplicates

A common variant allows the same value to be stored more than once and still requires uniform random selection across all stored copies. The array stays the same, but a single value → index map cannot track several positions for one value. Replace it with value → set of indices. Insert appends and adds the new index to that value's set; remove pulls any one index from the set (and the swapped-in element updates its own set: remove the old last index, add the new one); getRandom still picks a uniform array index. Each operation stays O(1) on average because set insertion, removal, and membership are all O(1).