Problem Overview
You need to design a data structure that supports the following operations in average O(1) time complexity:
- insert(val) – Inserts an element
valinto the set if it is not already present. - remove(val) – Removes an element
valfrom the set if it exists. - getRandom() – Returns a random element from the current set. Each element must have an equal probability of being returned.
Example:
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);→ returns truerandomizedSet.remove(2);→ returns falserandomizedSet.insert(2);→ returns truerandomizedSet.getRandom();→ returns either 1 or 2randomizedSet.remove(1);→ returns truerandomizedSet.insert(2);→ returns false (2 already exists)randomizedSet.getRandom();→ returns 2
Intuition / Approach
We need O(1) time for insert, remove, and getRandom, which rules out typical data structures like plain lists or sets.
We can achieve this by combining:
- A HashMap (for O(1) access and removal by value)
- An ArrayList (for O(1) random access by index)
Key Idea:
- Store elements in an ArrayList.
- Keep a HashMap mapping each element to its index in the list.
- To remove in O(1):
- Swap the element to be removed with the last element in the list.
- Update the index of the swapped element in the map.
- Remove the last element from the list.
This avoids O(n) time removal that a normal list would cause.
Step-by-Step Algorithm Explanation
- Insert(val)
- If
valis already in the map → returnfalse. - Otherwise:
- Add
valto the end of the list. - Record its index in the map.
- Return
true.
- Add
- If
- Remove(val)
- If
valis not in the map → returnfalse. - Otherwise:
- Retrieve the index of
valfrom the map. - Get the last element in the list.
- Swap the last element with
valin the list. - Update the index of the last element in the map.
- Remove the last element from the list.
- Remove
valfrom the map. - Return
true.
- Retrieve the index of
- If
- getRandom()
- Generate a random index between
0andlist.size() - 1. - Return the element at that index.
- Generate a random index between
Example Walkthrough
Let’s perform the following operations:
RandomizedSet set = new RandomizedSet(); set.insert(10); // [10] set.insert(20); // [10, 20] set.remove(10); // swap and remove -> [20] set.getRandom(); // returns 20
Step-by-step:
- insert(10) → list: [10], map: {10 → 0}
- insert(20) → list: [10, 20], map: {10 → 0, 20 → 1}
- remove(10):
- index = 0, lastElement = 20
- swap → list becomes [20, 10]
- remove last → list = [20]
- update map: {20 → 0}
- getRandom() → random index 0 → returns 20
Java Code Implementation
import java.util.*;
public class RandomizedSet {
private Map<Integer, Integer> map; // Stores value → index mapping
private List<Integer> list; // Stores elements for random access
private Random rand; // Random generator
public RandomizedSet() {
map = new HashMap<>();
list = new ArrayList<>();
rand = new Random();
}
public boolean insert(int val) {
if (map.containsKey(val)) {
return false; // Already exists
}
list.add(val);
map.put(val, list.size() - 1);
return true;
}
public boolean remove(int val) {
if (!map.containsKey(val)) {
return false; // Not present
}
int index = map.get(val);
int lastElement = list.get(list.size() - 1);
// Swap val with last element
list.set(index, lastElement);
map.put(lastElement, index);
// Remove last element
list.remove(list.size() - 1);
map.remove(val);
return true;
}
public int getRandom() {
int randomIndex = rand.nextInt(list.size());
return list.get(randomIndex);
}
}
Complexity Analysis
- Time Complexity:
insert()→ O(1)remove()→ O(1)getRandom()→ O(1)
- Space Complexity:
- O(n) for storing up to n elements in both the list and map.
Alternative Approaches
- Using LinkedHashSet:
- Allows quick insertion and deletion, but
getRandom()is O(n) because random access isn’t supported. - Not acceptable for O(1) requirement.
- Allows quick insertion and deletion, but
- Using TreeSet:
- Maintains sorted order but has O(log n) operations — slower than needed.
Hence, combining HashMap + ArrayList is the only way to achieve true O(1) performance for all operations.
