Verify and modify inorder subsequence
Company: Airbnb
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates algorithm design and data-structure manipulation in the Coding & Algorithms domain, focusing on binary tree inorder traversal, subsequence detection, and computing the minimum edit operations under strict time and space constraints.
Part 1: Verify an Inorder Subsequence with Morris Traversal
Constraints
- 0 <= number of serialized entries in tree <= 100000
- 0 <= len(sequence) <= 100000
- If tree is non-empty, tree[0] is not None
- Node values and sequence values are integers in the range [-10^9, 10^9]
- Duplicate values are allowed
Examples
Input: ([2, 1, 3], [1, 3])
Expected Output: True
Explanation: The inorder traversal is [1, 2, 3], and [1, 3] appears in order.
Input: ([2, 1, 3], [3, 1])
Expected Output: False
Explanation: The values exist, but not in inorder subsequence order.
Input: ([], [])
Expected Output: True
Explanation: The empty sequence is a subsequence of the empty traversal.
Input: ([], [1])
Expected Output: False
Explanation: A non-empty sequence cannot be a subsequence of an empty traversal.
Input: ([4, 2, 6, 1, 3, 5, 7], [1, 3, 7])
Expected Output: True
Explanation: The inorder traversal is [1, 2, 3, 4, 5, 6, 7], so [1, 3, 7] is a subsequence.
Hints
- You only need one pointer into sequence while scanning the inorder traversal.
- Morris traversal visits nodes in inorder without a recursion stack by temporarily threading predecessor pointers.
Part 2: Modify the Tree by Appending the Unmatched Inorder Suffix
Constraints
- 0 <= number of serialized entries in tree <= 10000
- 0 <= len(sequence) <= 10000
- If tree is non-empty, tree[0] is not None
- Values are integers in the range [-10^9, 10^9]
- Duplicate values are allowed
Examples
Input: ([2, 1, 3], [1, 4])
Expected Output: [2, 1, 3, None, None, None, 4]
Explanation: The original inorder is [1, 2, 3], which matches prefix [1]. The remaining value 4 is appended at the end as a new right child of the inorder-last node.
Input: ([2, 1, 3], [1, 2])
Expected Output: [2, 1, 3]
Explanation: The sequence is already a subsequence of the original inorder traversal, so no nodes are added.
Input: ([], [5, 6])
Expected Output: [5, None, 6]
Explanation: An empty tree becomes a right-skewed chain 5 -> 6.
Input: ([7], [])
Expected Output: [7]
Explanation: An empty target sequence needs no modification.
Input: ([], [])
Expected Output: []
Explanation: Both the tree and sequence are empty, so the result is an empty tree.
Hints
- Greedily match as much of the sequence as possible during an inorder traversal of the original tree.
- Adding a right-child chain to the inorder-last node appends values at the very end of the inorder traversal.
Part 3: Minimum Operations to Force an Inorder Subsequence
Constraints
- 0 <= number of serialized entries in tree <= 2000
- 0 <= len(sequence) <= 2000
- If tree is non-empty, tree[0] is not None
- Values are integers in the range [-10^9, 10^9]
- Duplicate values are allowed
Examples
Input: ([2, 1, 3], [1, 3])
Expected Output: 0
Explanation: The inorder traversal is already [1, 2, 3], so the target sequence already appears.
Input: ([2, 1, 3], [1, 4, 3])
Expected Output: 1
Explanation: Keep 1 and 3, then either change the middle node to 4 or insert 4 once.
Input: ([1], [2, 3])
Expected Output: 2
Explanation: There are no exact inorder matches with the target, so two target values must be created using two operations.
Input: ([], [])
Expected Output: 0
Explanation: No changes are required.
Input: ([1, None, 2], [2, 1])
Expected Output: 1
Explanation: The original inorder is [1, 2]. One insertion can make [2, 1] appear as a subsequence.
Hints
- A target value costs 0 only if you can keep some existing inorder node with the same value in the correct relative order.
- So the problem becomes: maximize how many target values are already matched in order, then pay 1 for every remaining target value.