Assign Ads to Browser Positions
Company: eBay
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates algorithmic problem-solving around randomized selection, constraint-based resource allocation, and per-user state management, including enforcing eligibility rules and incrementing display counts.
Constraints
- 0 <= len(positions) <= 200
- 0 <= len(candidateAds) <= 200
- All values in `positions` are distinct strings
- All `adId` values in `candidateAds` are unique
- 0 <= perUserLimit <= 10^9
- 0 <= userAdState[adId] <= 10^9 for any key present
- If an `adId` is missing from `userAdState`, treat its current count as 0
Examples
Input: (['top', 'middle', 'bottom'], [{'adId': 'ad_a', 'perUserLimit': 2}, {'adId': 'ad_b', 'perUserLimit': 1}, {'adId': 'ad_c', 'perUserLimit': 3}], {'ad_a': 1, 'ad_b': 1}, 5)
Expected Output: ({'top': 'ad_a', 'middle': 'ad_c', 'bottom': 'ad_c'}, {'ad_a': 2, 'ad_b': 1, 'ad_c': 2})
Explanation: Initially only `ad_a` and `ad_c` are eligible, so duplicates are allowed. The seeded choices pick `ad_a`, then `ad_c`, then `ad_c` again.
Input: (['left', 'right'], [{'adId': 'a', 'perUserLimit': 1}, {'adId': 'b', 'perUserLimit': 1}, {'adId': 'c', 'perUserLimit': 1}], {}, 1)
Expected Output: ({'left': 'b', 'right': 'c'}, {'b': 1, 'c': 1})
Explanation: There are at least as many eligible ads as positions, so no ad may be repeated in this call. The seeded picks choose `b` first, then `c` from the remaining pool.
Input: (['p1', 'p2'], [{'adId': 'x', 'perUserLimit': 1}], {'x': 1}, 7)
Expected Output: ({'p1': None, 'p2': None}, {'x': 1})
Explanation: The only ad has already reached its per-user limit, so no position can be filled.
Input: ([], [{'adId': 'x', 'perUserLimit': 2}], {'x': 1}, 9)
Expected Output: ({}, {'x': 1})
Explanation: With no positions, nothing is assigned and the state does not change.
Input: (['a', 'b', 'c', 'd'], [{'adId': 'u', 'perUserLimit': 2}, {'adId': 'v', 'perUserLimit': 2}, {'adId': 'w', 'perUserLimit': 1}], {'u': 1}, 2)
Expected Output: ({'a': 'u', 'b': 'v', 'c': 'w', 'd': 'v'}, {'u': 2, 'v': 2, 'w': 1})
Explanation: Only three ads are initially eligible for four positions, so duplicates are allowed. The seeded process fills all four positions while respecting remaining limits.
Input: (['p1', 'p2', 'p3'], [{'adId': 'only', 'perUserLimit': 1}], {}, 4)
Expected Output: ({'p1': 'only', 'p2': None, 'p3': None}, {'only': 1})
Explanation: The single ad can be shown once, so the first position is filled and the rest remain unassigned.
Hints
- First compute each ad's remaining capacity: `perUserLimit - currentCount`, but never let it go below 0.
- Decide once at the beginning whether duplicates are forbidden. If enough unique eligible ads exist, sample without replacement; otherwise, rebuild the eligible pool before each position.