Flatten Binary Tree to Linked List — LC 114 In-Place O(1) Space
Advertisement
Problem Statement
LeetCode 114 — Flatten Binary Tree to Linked List | Difficulty: Medium
Given the root of a binary tree, flatten the tree into a linked list in-place. The linked list should use the same TreeNode class where right is the next pointer and left is always null. The order must match pre-order traversal.
Constraints:
- The number of nodes is in the range
[0, 2000] -100 <= Node.val <= 100
Input: root = [1,2,5,3,4,null,6]
Output: [1,null,2,null,3,null,4,null,5,null,6]Input: root = []
Output: []Why This Problem Matters
Flatten Binary Tree to Linked List is a classic in-place tree manipulation problem asked at Amazon and Microsoft. It tests whether you can restructure a tree without allocating extra memory — a skill relevant to memory-constrained environments. The naive approach (collect nodes in pre-order, then rewire) is O(n) space; interviewers want the O(1) space iterative solution.
The core technique — finding the rightmost node of a subtree and attaching another subtree to it — is the same trick used in Morris traversal. Understanding this problem gives you a foundation for the full Morris in-order traversal algorithm, which itself appears in follow-up interview questions about iterative tree traversal with O(1) space.
The Core Insight
For each node, the pre-order sequence is: current → left subtree → right subtree. To flatten in-place:
- Find the rightmost node of the left subtree (the last node visited in the left subtree's pre-order).
- Attach the current right subtree to that rightmost node's right pointer.
- Move the entire left subtree to the right.
- Set the left pointer to null.
- Advance to
node.rightand repeat.
This works because after step 3, node.right contains the flattened left subtree, and the original right subtree is now appended at its end — exactly pre-order order.
Visual Dry Run
Tree: [1, 2, 5, 3, 4, null, 6]
| Step | Current | Action |
|---|---|---|
| 1 | node=1 | Has left child (2). Find rightmost of left subtree: 2→right→4 (rightmost). |
| 2 | node=1 | Attach right subtree (5→6) to node 4's right. |
| 3 | node=1 | Move left (2→3→4→5→6) to right. Set left=null. |
| 4 | node=2 | Has left child (3). Rightmost of left = 3. No right to attach. Move left to right. |
| 5 | node=3 | No left child. Advance to right. |
| 6 | Continue | Advance through 4, 5, 6 — none have left children. |
Result: 1 → 2 → 3 → 4 → 5 → 6 (all right pointers, all left=null).
Solution (Optimal)
class Solution:
def flatten(self, root) -> None:
node = root
while node:
if node.left:
# Find the rightmost node in the left subtree
tail = node.left
while tail.right:
tail = tail.right
# Attach current right subtree after the tail
tail.right = node.right
# Move left subtree to right
node.right = node.left
node.left = None
# Advance to next node (pre-order: now process right child)
node = node.rightvar flatten = function(root) {
let node = root;
while (node) {
if (node.left) {
// Find rightmost node of left subtree
let tail = node.left;
while (tail.right) {
tail = tail.right;
}
// Attach current right subtree at tail
tail.right = node.right;
// Move left subtree to right position
node.right = node.left;
node.left = null;
}
node = node.right;
}
};Time: O(n) — each node visited a constant number of times (at most twice: once as current, once as tail) Space: O(1) — no recursion stack, no extra data structures
Common Mistakes
- Using O(n) space by collecting all nodes in a list and rewiring — valid but misses the O(1) space insight interviewers want
- Forgetting to set
node.left = nullafter moving the left subtree to the right - Not finding the rightmost node of the left subtree (just using the left child directly would break the pre-order order)
- Advancing to
node.leftinstead ofnode.rightafter the rearrangement - Recursive approach forgetting to handle the case where the right subtree needs to be attached after recursion
Interview Tips
- Start by explaining the O(n) space approach (pre-order traversal into a list), then improve to O(1)
- Draw the tail-finding step clearly — interviewers trip candidates up on this detail
- The iterative O(1) solution is what gets you the offer; the recursive solution is acceptable but not optimal
- Mention that this technique is related to Morris traversal
Follow-up Questions
- How would you do this recursively? Post-order recursion: flatten left, flatten right, then insert flattened-left between root and flattened-right.
- What if you want the list in in-order or post-order? You would need to recurse and rewire pointers differently — the iterative approach is tailored to pre-order specifically.
- How does this relate to Morris traversal? Morris traversal uses the same "find rightmost of left subtree" trick to temporarily thread nodes for O(1) space traversal.
- Can this be done if the tree is not binary? For n-ary trees, you would need to flatten all children chains before stitching them together right-to-left.
- What is the time complexity of the naive recursive approach? Also O(n) but with O(h) space for the call stack.
Key Takeaways
- Flatten Binary Tree uses the "rightmost of left subtree" pointer as a connection point — the same trick as Morris traversal
- The iterative O(1) space solution processes each node exactly once: find tail, attach right, move left, advance
- Always set
node.left = nullafter moving the left subtree to avoid a corrupted tree - Pre-order flattening means: current node first, then left subtree, then right subtree
- Time is O(n) and space is O(1) — better than the O(n) space list-based approach
- The tail-finding inner loop looks O(n) per step but amortizes to O(n) total across all iterations
- This problem demonstrates that in-place tree restructuring is always possible by threading pointers carefully
Advertisement