Implement Batched Undo/Redo Layer
Company: Google
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: easy
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of state management, undo/redo semantics, batched transactional edits, and memory-efficient change history representation for map-based document layers.
Part 1: Implement Batched Undo/Redo for Document Properties
Constraints
- 0 <= len(operations) <= 200000
- The total number of ('set', key, value) operations is at most 200000
- Keys and values are strings of length 1 to 50
- Batches are not nested
- If a batch contains no set operations, committing it does not create history
Examples
Input: [('begin',), ('set', 'color', 'red'), ('end',), ('snapshot',), ('undo',), ('snapshot',), ('redo',), ('snapshot',)]
Expected Output: [{'color': 'red'}, {}, {'color': 'red'}]
Explanation: A single batch is committed, undone, and redone.
Input: [('begin',), ('set', 'a', '1'), ('end',), ('begin',), ('set', 'a', '2'), ('set', 'a', '3'), ('set', 'b', '9'), ('end',), ('snapshot',), ('undo',), ('snapshot',), ('redo',), ('snapshot',)]
Expected Output: [{'a': '3', 'b': '9'}, {'a': '1'}, {'a': '3', 'b': '9'}]
Explanation: The second batch updates 'a' twice and adds 'b'. Undo must restore the exact pre-batch state.
Hints
- For each key touched in the current batch, record its old value only the first time that key is edited in the batch.
- Use two stacks: one for committed batches that can be undone, and one for undone batches that can be redone. Clear the redo stack when a new non-empty batch is committed.
Part 2: Compact a Batch into Memory-Efficient Change Records
Constraints
- 0 <= len(initial_document) <= 200000
- 0 <= len(edits) <= 200000
- Keys and values are strings of length 1 to 50
- Each edit is a set operation only
- The output order of 'changes' must follow the first time each key appears in edits
Examples
Input: ({'a': '1', 'b': '2'}, [('a', '3'), ('a', '4'), ('c', '5')])
Expected Output: {'changes': [('a', '4', '1', True), ('c', '5', None, False)], 'after_apply': {'a': '4', 'b': '2', 'c': '5'}, 'after_undo': {'a': '1', 'b': '2'}, 'after_redo': {'a': '4', 'b': '2', 'c': '5'}}
Explanation: Repeated edits to 'a' collapse into one record that keeps the original old value and the final new value.
Input: ({}, [('x', '1'), ('x', '2'), ('x', '3')])
Expected Output: {'changes': [('x', '3', None, False)], 'after_apply': {'x': '3'}, 'after_undo': {}, 'after_redo': {'x': '3'}}
Explanation: Edge case: a new key is written multiple times in an otherwise empty document.
Hints
- When a key appears for the first time in the batch, capture its old value from the pre-batch document, not from any earlier edit in the same batch.
- For later edits to the same key, update only the final value in its compact record.