Implement undo/redo with two stacks
Company: Airtable
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates a candidate's ability to design and implement efficient mutable state management and history tracking using data structures (such as stacks), along with string manipulation and algorithmic complexity reasoning.
Constraints
- 0 <= len(commands) <= 2 * 10^5
- The total number of characters across all `TYPE` commands is at most 2 * 10^5
- Each command is valid and follows one of these formats exactly: `TYPE s`, `DELETE k`, `UNDO`, `REDO`
- 0 <= k <= 2 * 10^5
Examples
Input: (["TYPE abc", "TYPE d", "DELETE 2", "UNDO", "REDO"],)
Expected Output: ["abc", "abcd", "ab", "abcd", "ab"]
Explanation: This is the basic undo/redo flow: type, type, delete, undo the delete, then redo it.
Input: (["UNDO", "TYPE hi", "DELETE 5", "UNDO", "REDO", "REDO"],)
Expected Output: ["", "hi", "", "hi", "", ""]
Explanation: The first UNDO does nothing. DELETE 5 removes all of "hi". The last REDO also does nothing because there is nothing left to redo.
Input: (["TYPE a", "TYPE bc", "UNDO", "TYPE d", "REDO", "DELETE 2", "UNDO"],)
Expected Output: ["a", "abc", "a", "ad", "ad", "", "ad"]
Explanation: After UNDO, typing `d` clears the redo history, so the later REDO has no effect.
Input: ([],)
Expected Output: []
Explanation: No commands means no outputs.
Input: (["TYPE hello", "DELETE 2", "TYPE y", "UNDO", "UNDO", "REDO", "TYPE !", "UNDO", "REDO"],)
Expected Output: ["hello", "hel", "hely", "hel", "hello", "hel", "hel!", "hel", "hel!"]
Explanation: This case checks multiple undos/redos and verifies that a new TYPE clears the redo stack.
Hints
- Use one stack for applied mutating operations and another stack for operations that were undone and could be redone.
- For a `DELETE`, store the actual removed substring, not just `k`, so that an `UNDO` can restore the text exactly.