Insert Delete GetRandom O(1)
Hash map of value to index plus a dense vector — swap-with-last for O(1) delete, uniform random by index.
3 min read
design hash-map array
Problem#
Implement a set supporting insert(val), remove(val), and getRandom() — each in average O(1). getRandom must return any current element with uniform probability.
Examples#
insert(1); insert(2); getRandom()→1or2with 1/2 each.remove(1); getRandom()→2.
Constraints#
-2^31 <= val <= 2^31 - 1, up to2 * 10^5ops.
Approach#
Maintain a vector<int> vals (dense), and unordered_map<int,int> pos from value to its index in vals. To delete, swap the target with the last element, pop the last, update the moved element’s position.
Solution#
class RandomizedSet { vector<int> vals; unordered_map<int,int> pos;public: bool insert(int val) { if (pos.count(val)) return false; pos[val] = vals.size(); vals.push_back(val); return true; } bool remove(int val) { auto it = pos.find(val); if (it == pos.end()) return false; int idx = it->second, last = vals.back(); vals[idx] = last; pos[last] = idx; vals.pop_back(); pos.erase(it); return true; } int getRandom() { return vals[rand() % vals.size()]; }};import "math/rand"
type RandomizedSet struct { vals []int pos map[int]int}
func Constructor() RandomizedSet { return RandomizedSet{pos: map[int]int{}}}
func (s *RandomizedSet) Insert(val int) bool { if _, ok := s.pos[val]; ok { return false } s.pos[val] = len(s.vals) s.vals = append(s.vals, val) return true}
func (s *RandomizedSet) Remove(val int) bool { idx, ok := s.pos[val] if !ok { return false } last := s.vals[len(s.vals)-1] s.vals[idx] = last s.pos[last] = idx s.vals = s.vals[:len(s.vals)-1] delete(s.pos, val) return true}
func (s *RandomizedSet) GetRandom() int { return s.vals[rand.Intn(len(s.vals))]}import random
class RandomizedSet: def __init__(self): self.vals: list = [] self.pos: dict = {}
def insert(self, val: int) -> bool: if val in self.pos: return False self.pos[val] = len(self.vals) self.vals.append(val) return True
def remove(self, val: int) -> bool: if val not in self.pos: return False idx = self.pos[val] last = self.vals[-1] self.vals[idx] = last self.pos[last] = idx self.vals.pop() del self.pos[val] return True
def getRandom(self) -> int: return random.choice(self.vals)class RandomizedSet { constructor() { this.vals = []; this.pos = new Map(); }
insert(val) { if (this.pos.has(val)) return false; this.pos.set(val, this.vals.length); this.vals.push(val); return true; }
remove(val) { if (!this.pos.has(val)) return false; const idx = this.pos.get(val); const last = this.vals[this.vals.length - 1]; this.vals[idx] = last; this.pos.set(last, idx); this.vals.pop(); this.pos.delete(val); return true; }
getRandom() { return this.vals[Math.floor(Math.random() * this.vals.length)]; }}class RandomizedSet { private List<Integer> vals = new ArrayList<>(); private Map<Integer, Integer> pos = new HashMap<>(); private Random rng = new Random();
public boolean insert(int val) { if (pos.containsKey(val)) return false; pos.put(val, vals.size()); vals.add(val); return true; }
public boolean remove(int val) { Integer idx = pos.get(val); if (idx == null) return false; int last = vals.get(vals.size() - 1); vals.set(idx, last); pos.put(last, idx); vals.remove(vals.size() - 1); pos.remove(val); return true; }
public int getRandom() { return vals.get(rng.nextInt(vals.size())); }}class RandomizedSet { private vals: number[] = []; private pos: Map<number, number> = new Map();
insert(val: number): boolean { if (this.pos.has(val)) return false; this.pos.set(val, this.vals.length); this.vals.push(val); return true; }
remove(val: number): boolean { if (!this.pos.has(val)) return false; const idx = this.pos.get(val)!; const last = this.vals[this.vals.length - 1]; this.vals[idx] = last; this.pos.set(last, idx); this.vals.pop(); this.pos.delete(val); return true; }
getRandom(): number { return this.vals[Math.floor(Math.random() * this.vals.length)]; }}Editorial#
The dense vector is essential for uniform-random O(1) selection. Naive deletion would be O(n); the swap-with-last trick keeps the vector compact without preserving order — which we don’t need.
Complexity#
- Time:
O(1)average per op. - Space:
O(n).
Concept revision#
Related#