Solve Throughput, Rate Limiting, and LFU
Company: Microsoft
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Onsite
Quick Answer: This set of tasks evaluates algorithmic problem-solving, data structure design, and systems-oriented reasoning by testing throughput calculation, rolling-window rate limiting, and LFU cache eviction with O(1) access constraints.
Part 1: Minimum Processing Speed
Constraints
- 1 <= len(piles) <= 100000
- 1 <= piles[i] <= 1000000000
- 1 <= h <= 1000000000
- h >= len(piles)
Examples
Input: ([3, 6, 7, 11], 8)
Expected Output: 4
Explanation: At k = 4, the hours needed are 1 + 2 + 2 + 3 = 8. Any smaller speed needs more than 8 hours.
Input: ([30, 11, 23, 4, 20], 5)
Expected Output: 30
Explanation: There are 5 piles and only 5 hours, so every pile must finish in one hour. The speed must be at least the largest pile.
Input: ([30, 11, 23, 4, 20], 6)
Expected Output: 23
Explanation: With k = 23, the hours needed are 2 + 1 + 1 + 1 + 1 = 6.
Input: ([1000000000], 2)
Expected Output: 500000000
Explanation: A single pile of 1,000,000,000 items completed over 2 hours needs ceiling(1000000000 / 2).
Hints
- If you fix a speed k, you can compute the hours needed for each pile independently using ceiling division.
- As k increases, the total hours needed never increases. That monotonic behavior suggests binary search.
Part 2: Rolling Window Rate Limiter
Constraints
- 0 <= limit <= 100000
- 1 <= window_seconds <= 1000000000
- 0 <= len(user_ids) == len(timestamps) <= 200000
- timestamps is non-decreasing
- user_ids[i] is a non-empty string
Examples
Input: (2, 5, ['alice', 'alice', 'alice', 'alice'], [1, 2, 3, 7])
Expected Output: [True, True, False, True]
Explanation: The first two requests are allowed. The third is blocked because two allowed requests still fall inside the last 5 seconds. By time 7, the earlier allowed requests have expired.
Input: (2, 3, ['a', 'b', 'a', 'a', 'b'], [1, 1, 2, 3, 4])
Expected Output: [True, True, True, False, True]
Explanation: Each user is tracked independently. User 'a' is blocked on the fourth call, while user 'b' is allowed again once the earlier request falls out of the window.
Input: (1, 10, ['x', 'x', 'x'], [5, 15, 16])
Expected Output: [True, True, False]
Explanation: The request at time 5 expires exactly when the timestamp reaches 15 because the window is (t - 10, t].
Input: (3, 60, [], [])
Expected Output: []
Explanation: No calls means no output.
Input: (0, 10, ['u', 'u'], [1, 2])
Expected Output: [False, False]
Explanation: If the limit is 0, no request can ever be accepted.
Hints
- Store request history separately for each user.
- Because timestamps are non-decreasing, expired timestamps can be removed from the front of a queue.
Part 3: LFU Cache with LRU Tie-Breaking
Constraints
- 0 <= capacity <= 200000
- 0 <= len(operations) == len(keys) == len(values) <= 200000
- operations[i] is either 'put' or 'get'
- -1000000000 <= keys[i], values[i] <= 1000000000
Examples
Input: (2, ['put', 'put', 'get', 'put', 'get', 'get'], [1, 2, 1, 3, 2, 3], [1, 2, 0, 3, 0, 0])
Expected Output: [1, -1, 3]
Explanation: After key 1 is accessed, key 2 has the lower frequency and is evicted when key 3 is inserted.
Input: (2, ['put', 'put', 'put', 'get', 'get'], [1, 2, 3, 1, 3], [10, 20, 30, 0, 0])
Expected Output: [-1, 30]
Explanation: Keys 1 and 2 both have frequency 1 when key 3 is inserted, so the least recently used among them, key 1, is evicted.
Input: (2, ['put', 'put', 'put', 'get', 'get'], [1, 2, 2, 1, 2], [1, 2, 20, 0, 0])
Expected Output: [1, 20]
Explanation: Updating key 2 changes its value to 20 and also increases its frequency.
Input: (0, ['put', 'get'], [1, 1], [1, 0])
Expected Output: [-1]
Explanation: A zero-capacity cache cannot store any entries.
Hints
- You need fast lookup by key and fast eviction by frequency.
- Group keys by frequency, and within each frequency group keep keys in least-recently-used order.