Implement a debounce function
Company: Apple
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's ability to implement a debounce utility using runtime features such as closures, timers, and function-context preservation, testing competencies in function design, stateful behavior, and event-rate control within the Coding & Algorithms domain.
Part 1: Simulate Basic Debounce(fn, wait)
Constraints
- 0 <= len(events) <= 200000
- 0 <= wait <= 10^9
- Event times are integers in nondecreasing order.
- If multiple calls share the same time, they appear in the exact order they occur.
Examples
Input: ([(0, 'A', 1), (2, 'B', 2), (7, 'C', 3)], 5)
Expected Output: [(7, 'B', 2), (12, 'C', 3)]
Explanation: The call at time 2 replaces the earlier pending call. At time 7, the pending `(7, 'B', 2)` fires before the new call at time 7 is processed.
Input: ([(1, 'x', 10), (10, 'y', 20)], 3)
Expected Output: [(4, 'x', 10), (13, 'y', 20)]
Explanation: The calls are far enough apart that both invocations happen.
Input: ([], 4)
Expected Output: []
Explanation: No calls means no invocations.
Input: ([(5, 'a', 1), (5, 'b', 2), (6, 'c', 3)], 0)
Expected Output: [(5, 'a', 1), (5, 'b', 2), (6, 'c', 3)]
Explanation: With `wait = 0`, each pending invocation becomes due immediately and fires before the next same-time event is processed.
Hints
- Keep only one pending invocation at any moment: its fire time, context, and value.
- Before handling a new call at time `t`, check whether the previous pending invocation should fire first.
Part 2: Simulate Debounce with cancel()
Constraints
- 0 <= len(events) <= 200000
- 0 <= wait <= 10^9
- Event times are integers in nondecreasing order.
- If multiple events share the same time, they appear in the exact order they occur.
Examples
Input: ([('call', 0, 'A', 1), ('call', 2, 'B', 2), ('cancel', 4), ('call', 10, 'C', 3)], 5)
Expected Output: [(15, 'C', 3)]
Explanation: The pending call from time 2 is cancelled at time 4. Only the later call at time 10 survives.
Input: ([('cancel', 1), ('call', 3, 'X', 9)], 2)
Expected Output: [(5, 'X', 9)]
Explanation: Cancelling with no pending invocation does nothing.
Input: ([('call', 0, 'A', 1), ('cancel', 5)], 5)
Expected Output: [(5, 'A', 1)]
Explanation: The pending invocation is due at time 5, so it fires before the cancel event at the same time is processed.
Input: ([], 3)
Expected Output: []
Explanation: No events means no invocations.
Hints
- Reuse the basic debounce state: a single pending invocation tuple is enough.
- Handle any due invocation before processing the current event, especially for exact-time `cancel` events.
Part 3: Simulate Debounce with flush()
Constraints
- 0 <= len(events) <= 200000
- 0 <= wait <= 10^9
- Event times are integers in nondecreasing order.
- If multiple events share the same time, they appear in the exact order they occur.
Examples
Input: ([('call', 0, 'A', 1), ('call', 2, 'B', 2), ('flush', 4), ('call', 10, 'C', 3)], 5)
Expected Output: [(4, 'B', 2), (15, 'C', 3)]
Explanation: The latest pending call is flushed early at time 4. The later call at time 10 fires normally at time 15.
Input: ([('flush', 1), ('call', 3, 'X', 9)], 2)
Expected Output: [(5, 'X', 9)]
Explanation: Flushing when nothing is pending does nothing.
Input: ([('call', 0, 'A', 1), ('flush', 5)], 5)
Expected Output: [(5, 'A', 1)]
Explanation: The scheduled invocation is already due at time 5, so it fires before the flush event is processed.
Input: ([('call', 0, 'Z', 7), ('flush', 0)], 3)
Expected Output: [(0, 'Z', 7)]
Explanation: A flush can force the pending invocation to run immediately, even at the same timestamp as the call.
Hints
- A flush event is only meaningful if there is still a pending invocation after processing all due timers up to that time.
- For a `flush` event at time `t`, append `(t, latest_context, latest_value)` and clear the pending state.