Framework Thinking - Axon - Randomized Camera Checkout by Id - Constant Time - Insert/Delete/Random O(1)
Here is solutions for Randomized Camera Checkout by Id - Constant Time.
1. Understand the problem
✅ 1. Understand the Problem
-
We are building a camera checkout pool that stores camera IDs (integers) and supports:
-
insert(id) → add a camera back to the pool
-
remove(id) → remove a camera when it’s checked out
-
select_random() → return a random available camera ID
-
-
Requirements:
-
These operations will be called very frequently
-
The pool can be very large
-
Duplicates ARE allowed (senior-level add-on)
-
We must achieve O(1) average time for:
-
Insert
-
Remove
-
Get Random
-
-
-
So this is a high-performance randomized data structure problem.
2. Clarify constraints, asks 4 - 5 questions including edge cases.
Edge cases to consider
-
What happens if “GetRandom” API is called when collection is empty They will typically note here that the return type of “int” is unsuitable. Ask what the options are assuming the API is set in stone. (Good answer: Throw an exception/abort. Bad answer: Just reserve some integers, like 0, that can’t be put in the collection).
-
What happens if remove is called on the last element in the collection
-
What happens if I try and remove an integer that is not in the collection
-
What happens if I try to insert the same integer twice
3. Explore examples.
- Example 1
insert(10)
insert(20)
insert(10)
insert(30)
Pool = [10, 20, 10, 30]
- Example 2
remove(10)
-
Only one 10 is removed:
-
Pool could become: [30, 20, 10]
- Example 3
-
remove(99) → False
-
remove(20) → True
4. Brainstorm 2 - 3 solutions, naive solution first and optimize later. Explain the key idea of each solution.
4.1. Solution 1: Naive (List Only)
-
Use a list:
-
Insert → append → O(1)
-
Random → random.choice → O(1)
-
Remove → list.remove(id) → O(n) (linear scan)
-
4.2. 🟡 Solution 2: HashMap Only
id → count
-
Insert → O(1)
-
Remove → O(1)
❌ Random → Not possible in O(1), because:
- You don’t know how many total values exist
- You can’t directly pick a random occurrence
❌ Fails random selection requirement
4.3. Solution 3: Optimized O(1)
We need:
-
Random access → use a list
-
Fast lookup/removal with duplicates → use a hashmap of index sets
Data Structures:
- arr: dynamic list of all values
- pos: hashmap → id -> set of indices in arr
Why This Works:
-
Random selection → random index in arr
-
Insert → append to arr, store index in pos
-
Remove → use swap-with-last trick to delete in O(1)
5. Implement solutions.
import random
from collections import defaultdict
class CameraPool:
def __init__(self):
self.arr = [] # stores all camera ids
self.pos = defaultdict(set) # id -> set of indices
def insert(self, id: int) -> bool:
existed = id in self.pos and len(self.pos[id]) > 0
self.arr.append(id)
self.pos[id].add(len(self.arr) - 1)
return not existed
def remove(self, id: int) -> bool:
if id not in self.pos or len(self.pos[id]) == 0:
return False
# Get one index of this id
remove_idx = self.pos[id].pop()
last_val = self.arr[-1]
# Move last element to the removed spot
self.arr[remove_idx] = last_val
# Update last_val index set
self.pos[last_val].add(remove_idx)
self.pos[last_val].discard(len(self.arr) - 1)
# Remove last element
self.arr.pop()
return True
def select_random(self) -> int:
return random.choice(self.arr)
- Idea: Xoá cái index cuối, lấy last_val gán vô cái remove idx.
6. Dry run testcases.
arr = [5, 10, 5, 20]
pos = {
5: {0, 2},
10: {1}
20: {3}
}
- remove(5)
arr = [5, 10, 5, 20]
=> arr = [5, 10, 20, 20]
=> pop the last value => [5, 10, 20]
pos = {
5: {0},
10: {1}
20: {2}
}
=> Remove default value in a dict O(1)