Implement Cache, Undo, and DFS
Company: Netflix
Role: Software Engineer
Category: Coding & Algorithms
Interview Round: Onsite
Quick Answer: This question evaluates implementation skills in data structures, algorithmic complexity, and state-management patterns by combining a timed in-memory cache, a command-undo manager, and depth-first traversal of an organizational tree, and is categorized under Coding & Algorithms.
Part 1: Timed Cache Simulator
Constraints
- 0 <= len(operations) <= 2 * 10^5
- Timestamps used in `put`, `get`, and `cleanup` are non-decreasing integers.
- 0 <= ttl <= 10^9
- Keys are hashable Python literals such as strings or integers.
Examples
Input: [('put', 'a', 10, 5, 0), ('get', 'a', 3), ('get', 'a', 5), ('cleanup', 5), ('get', 'a', 6)]
Expected Output: [10, -1, 1, -1]
Explanation: Key 'a' expires at time 5. It is valid at time 3, expired at time 5, and cleanup physically removes it.
Input: [('put', 'x', 1, 10, 0), ('put', 'x', 2, 2, 1), ('cleanup', 4), ('get', 'x', 4), ('cleanup', 11), ('get', 'x', 11)]
Expected Output: [1, -1, 0, -1]
Explanation: The second put overwrites 'x' with an earlier expiration. The old heap record from the first put becomes stale and must be ignored later.
Input: [('delete', 'z'), ('put', 'z', 7, 3, 2), ('delete', 'z'), ('get', 'z', 3), ('cleanup', 10)]
Expected Output: [False, True, -1, 0]
Explanation: Deleting a missing key returns False. After deleting 'z', later get misses and cleanup removes nothing.
Input: [('put', 'k', 5, 0, 10), ('get', 'k', 10), ('cleanup', 10), ('get', 'k', 11)]
Expected Output: [-1, 1, -1]
Explanation: A ttl of 0 means the item expires immediately at insertion time.
Input: []
Expected Output: []
Explanation: No operations means no results.
Hints
- Use a hash map so `get(key, now)` only needs to inspect one key.
- A min-heap of `(expire_time, key)` pairs lets `cleanup(now)` remove expired candidates efficiently while skipping stale heap entries.
Part 2: Undo Manager for a Text Editor
Constraints
- 0 <= len(operations) <= 2 * 10^4
- For every `replace` command, `0 <= start <= end <= len(current_text)` at execution time.
- For every `delete` command, `k` is a non-negative integer.
- The total number of characters appearing in all appended and replacement strings is at most 2 * 10^5.
Examples
Input: [('append', 'abc'), ('append', 'de'), ('get',), ('delete', 2), ('get',), ('undo',), ('get',), ('replace', 1, 4, 'XYZ'), ('get',), ('undo',), ('get',), ('canUndo',)]
Expected Output: ['abcde', 'abc', 'abcde', 'aXYZe', 'abcde', True]
Explanation: Demonstrates append, delete, replace, and undo in sequence.
Input: [('canUndo',), ('undo',), ('get',)]
Expected Output: [False, '']
Explanation: Undo on empty history is a no-op.
Input: [('append', 'hi'), ('delete', 5), ('get',), ('undo',), ('get',)]
Expected Output: ['', 'hi']
Explanation: Deleting more characters than exist clears the document; undo restores it.
Input: [('replace', 0, 0, 'a'), ('get',), ('undo',), ('get',)]
Expected Output: ['a', '']
Explanation: A replace with `start == end` acts like insertion, and undo removes the inserted text.
Input: []
Expected Output: []
Explanation: No operations produce no query results.
Hints
- You do not need to snapshot the whole document after every command; store only the inverse information needed for undo.
- For `replace`, save the old substring and remember the range occupied by the new text so you can restore the old content later.
Part 3: Depth-First Traversal of an Organization Tree
Constraints
- 0 <= number of nodes <= 10^5
- Each node uses the format `{'id': value, 'children': [...]}`.
- Children must appear in the output in the same left-to-right order as listed in the input.
- Node ids may be integers or strings.
Examples
Input: None
Expected Output: []
Explanation: An empty tree has no traversal.
Input: {'id': 1, 'children': []}
Expected Output: [1]
Explanation: A single-node tree visits only its root.
Input: {'id': 'CEO', 'children': [{'id': 'CTO', 'children': [{'id': 'Dev1', 'children': []}, {'id': 'Dev2', 'children': []}]}, {'id': 'CFO', 'children': []}, {'id': 'COO', 'children': [{'id': 'Ops1', 'children': []}]}]}
Expected Output: ['CEO', 'CTO', 'Dev1', 'Dev2', 'CFO', 'COO', 'Ops1']
Explanation: This is a preorder traversal: parent first, then each child subtree from left to right.
Input: {'id': 10, 'children': [{'id': 20, 'children': []}, {'id': 30, 'children': [{'id': 40, 'children': []}, {'id': 50, 'children': []}, {'id': 60, 'children': []}]}]}
Expected Output: [10, 20, 30, 40, 50, 60]
Explanation: The tree has an arbitrary branching factor, not just binary children.
Input: {'id': 1, 'children': [{'id': 2, 'children': [{'id': 3, 'children': [{'id': 4, 'children': []}]}]}]}
Expected Output: [1, 2, 3, 4]
Explanation: A deep chain should still be traversed correctly.
Hints
- Preorder DFS visits the node before its children.
- If you use an explicit stack, push children in reverse order so they are processed left to right.