Simulate a Throttled Function Wrapper That Keeps Only the Latest Pending Call
Company: Microsoft
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
A throttle wrapper limits how often a function actually runs. You are given the cooldown length `t` and the times at which the wrapped function is called. Simulate the wrapper and report which calls actually execute, and when.
The wrapper behaves as follows:
- It starts idle. A call that arrives while the wrapper is idle executes immediately, at its own call time, and starts a cooldown of length `t`. A cooldown that starts at time `s` covers the half-open interval `[s, s + t)`.
- A call that arrives during an active cooldown does not run right away. It becomes the pending call, replacing any call that was already pending, so only the most recent arguments survive.
- When a cooldown ends at time `e = s + t`: if a call is pending, it executes at time `e`, the pending slot is cleared, and a new cooldown `[e, e + t)` begins. If nothing is pending, the wrapper becomes idle.
Return one `[execution_time, call_index]` pair for every execution, where `call_index` is the 0-based position in `call_times` of the call whose arguments were used.
### Function Signature
```python
def throttle_schedule(t: int, call_times: list[int]) -> list[list[int]]:
```
### Rules
- Calls are processed in input order. Several calls may share the same time; they are handled one after another in input order.
- Boundary rule: a call whose time equals the end `e` of the current cooldown is handled after the end-of-cooldown step at `e`. If a pending call fires at `e`, the new call falls inside the new cooldown and becomes pending. If nothing was pending, the wrapper is idle at `e` and the new call executes immediately at `e`.
- After the last call, keep simulating until the wrapper is idle, so a call that is still pending executes when its cooldown expires.
- A call that is replaced while pending never executes and does not appear in the output.
- Return the pairs in execution order. Execution times are strictly increasing, so this order is unique.
### Constraints
- `1 <= t <= 10^6`
- `1 <= len(call_times) <= 10^5`
- `0 <= call_times[i] <= 10^9`, and `call_times` is sorted in non-decreasing order
- Every execution time is at most `10^9 + 10^6`, which fits in a signed 32-bit integer.
### Examples
**Example 1**
- Input: `t = 10`, `call_times = [0, 3, 7, 12, 25, 30, 30]`
- Output: `[[0, 0], [10, 2], [20, 3], [30, 4], [40, 6]]`
- Explanation: call 0 runs at 0 and starts the cooldown `[0, 10)`. Calls 1 and 2 arrive during it; call 2 replaces call 1 and runs at 10, starting `[10, 20)`. Call 3 waits and runs at 20, starting `[20, 30)`. Call 4 waits and runs at 30, starting `[30, 40)`. The two calls at time 30 are handled after that step, so both fall into the new cooldown; call 6 replaces call 5 and runs at 40. Nothing is pending when that cooldown ends at 50, so the wrapper goes idle.
**Example 2**
- Input: `t = 5`, `call_times = [1, 6, 6, 20]`
- Output: `[[1, 0], [6, 1], [11, 2], [20, 3]]`
- Explanation: the cooldown started by call 0 ends at 6 with nothing pending, so the wrapper is idle and call 1 runs at 6, starting `[6, 11)`. Call 2, also at time 6, waits and runs at 11. That cooldown ends at 16 with nothing pending, so call 3 runs immediately at 20.
**Example 3**
- Input: `t = 3`, `call_times = [0, 1, 2]`
- Output: `[[0, 0], [3, 2]]`
- Explanation: call 0 runs at 0; call 2 replaces call 1 as the pending call and runs when the cooldown ends at 3.
Overview: A coding simulation of a throttle wrapper: given a cooldown length and sorted call times, report which calls actually run and when, where calls arriving during a cooldown keep only the latest one pending. It tests precise event ordering, an explicit rule for calls at the exact moment a cooldown ends, and an efficient single pass.
Read the full Microsoft Software Engineer interview experience this question came from