Simulate Constant-Time Random Courier Selection
DoorDashSoftware Engineer · Technical ScreenLast updated
Design a courier pool data structure that supports adding, removing, and uniformly selecting random courier IDs in average O(1) time.
Problem Description
DoorDash dispatch systems dynamically match incoming delivery orders with currently available dashers (couriers). To balance dispatch load fairly across a fleet, the system needs to maintain an active pool of available courier IDs and pick a courier uniformly at random when an order arrives.
Implement the CourierPool class:
__init__(): Initializes the courier pool.register_courier(courier_id: int) -> bool: Insertscourier_idinto the pool if it is not already present. ReturnsTrueif the courier was successfully registered, orFalseif the courier was already in the pool.deregister_courier(courier_id: int) -> bool: Removescourier_idfrom the pool if it is present. ReturnsTrueif the courier was successfully removed, orFalseif the courier was not found in the pool.get_random_courier() -> int: Returns a courier ID chosen uniformly at random from the pool of currently registered couriers. Each courier currently in the pool must have an equal probability of being selected. If the pool is empty, return-1.
Each function must run in average O(1) time complexity.
Class Interface
class CourierPool:
def __init__(self):
pass
def register_courier(self, courier_id: int) -> bool:
pass
def deregister_courier(self, courier_id: int) -> bool:
pass
def get_random_courier(self) -> int:
pass
Examples
Example 1
pool = CourierPool()
pool.register_courier(101) # returns True; pool: [101]
pool.deregister_courier(202) # returns False; 202 is not in pool
pool.register_courier(202) # returns True; pool: [101, 202]
pool.get_random_courier() # returns 101 or 202 with equal probability (50% each)
pool.deregister_courier(101) # returns True; pool: [202]
pool.register_courier(202) # returns False; 202 is already registered
pool.get_random_courier() # returns 202
Example 2
pool = CourierPool()
pool.get_random_courier() # returns -1 because pool is empty
Constraints
-2^31 <= courier_id <= 2^31 - 1- At most
2 * 10^5calls will be made in total toregister_courier,deregister_courier, andget_random_courier. - There will be at least one call to
get_random_courierwhen the pool is non-empty.
Hints
Hint 1
A standard hash set supports O(1) insertion and deletion, but sampling an element uniformly at random requires an indexed data structure like an array.
Hint 2
To remove an arbitrary element from an array in O(1) time without shifting elements, consider swapping the element to be removed with the last element before popping.
Hint 3
Maintain a hash map that maps each courier ID to its current index in the underlying array, and remember to update the index of the swapped element during removal.
Follow-up questions
- How would you modify this data structure to support weighted random courier selection based on acceptance ratings or proximity tiers in O(log n) or O(1) time?
- How would you ensure thread-safety for high-throughput concurrent reads and writes across multiple worker threads?
- If the pool of active couriers exceeds single-node memory or requires cross-datacenter availability, how would you distribute this system while maintaining uniform random sampling?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.