Implement a random fixed-size load balancer
Company: Revolut
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of randomized selection, efficient in-memory data structures, and API/state management for a fixed-capacity load balancer that must support addNode, removeNode, and uniform random routing while handling duplicates, removals, and empty-state behavior.
Constraints
- 0 <= number of operations <= 10^5
- 1 <= capacity (K) <= 10^4
- Node ids are non-empty strings (or comparable hashable ids).
- addNode at capacity K is rejected (returns False).
- removeNode on an absent node is a no-op (returns False).
- route() on an empty set returns None.
- Each operation should run in O(1) amortized time.
Examples
Input: ([['add', 'A'], ['add', 'B'], ['add', 'A'], ['route', None], ['remove', 'B'], ['remove', 'B'], ['route', None]], 2, 42)
Expected Output: [True, True, False, 'A', True, False, 'A']
Explanation: Add A and B (capacity 2). Adding A again is a duplicate -> False. route() with seed 42 returns 'A'. Remove B -> True; removing B again is a no-op -> False. With only A left, route() returns 'A'.
Input: ([['route', None]], 3, 1)
Expected Output: [None]
Explanation: Routing when there are no active nodes returns None.
Input: ([['add', 'n1'], ['add', 'n2'], ['add', 'n3'], ['add', 'n4']], 3, 7)
Expected Output: [True, True, True, False]
Explanation: Capacity K is 3. The first three adds succeed; the fourth is rejected because the load balancer is full -> False.
Input: ([], 5, 0)
Expected Output: []
Explanation: No operations -> empty result list.
Input: ([['add', 'x'], ['route', None], ['remove', 'x'], ['route', None]], 1, 99)
Expected Output: [True, 'x', True, None]
Explanation: Add 'x' -> True. With one node, route() returns 'x'. Remove 'x' -> True. Now empty, so route() returns None.
Hints
- Maintain a flat list of active node ids so you can pick a random one in O(1) via an index.
- Maintain a hash map node_id -> index_in_list for O(1) membership checks and removals.
- To remove a node in O(1) without shifting, swap it with the last element, pop the last, and update the swapped element's index in the map.
- Guard the three edge cases explicitly: duplicate add, at-capacity add, remove-of-absent, and route-when-empty.