Problem Walkthrough

Flatten Binary Tree LeetCode 114 Guide

Master LeetCode 114 by learning three distinct approaches: the elegant reverse-postorder recursive solution that builds the flattened list from tail to head, the iterative stack method that simulates preorder traversal, and Morris traversal which rewires the tree in-place with O(1) extra space — the answer to the hardest follow-up question in the problem.

9 min read|

Flatten Binary Tree

LeetCode 114

Problem Overview

LeetCode 114 — Flatten Binary Tree to Linked List — gives you the root of a binary tree and asks you to flatten it to a linked list in-place. The list must follow preorder traversal order: root, then all nodes from the left subtree, then all nodes from the right subtree. The catch: you must use the existing tree nodes, setting each node's right pointer to the next node in preorder sequence, and every left pointer must be set to null.

The problem looks simple on the surface — it is essentially converting a tree to a list — but the in-place constraint changes everything. You cannot build a separate list and then reassign pointers; you must rewire as you traverse. The tricky part is that modifying a node's pointers while traversing can destroy the information you need to continue. Each approach below handles this differently.

There is a well-known follow-up question: can you do it with O(1) extra space? The recursive and iterative stack solutions both use O(h) space for the call stack or explicit stack, where h is the tree height. The Morris traversal solution is the intended O(1) answer. Understanding all three gives you a complete picture of the problem.

  • Constraints: number of nodes is in [0, 2000]
  • Node values are in the range [-100, 100]
  • Flatten must happen in-place — do not return a new list, modify the tree directly
  • After flattening, every node.left must be null
  • After flattening, every node.right points to the next node in preorder order
  • The resulting structure should look like a singly linked list using the right child pointer

Recursive Approach (Reverse Postorder)

The recursive approach processes nodes in reverse preorder — right subtree first, then left subtree, then the root — and maintains a global prev pointer that always points to the previously processed node. At each node, set node.right = prev, set node.left = null, then update prev = node. When the recursion unwinds, each node's right pointer has been set to the correct next node in preorder.

This works because reverse preorder visits nodes in the exact reverse of the desired output order. By building the list from tail to head, each node's right pointer is set to the node that should come after it — and that node has already been fully processed before we assign the pointer. There is no risk of destroying traversal state because we have already finished traversing the subtree.

The key insight is that "reverse preorder" (right → left → root) visits root last, which means by the time you process the root, both subtrees have been fully wired up. The prev pointer at that moment is the leftmost node of what was originally the left subtree — exactly where the root should point in the flattened result.

💡

Why Process Right Before Left

Processing right-then-left-then-root is reverse preorder, which naturally builds the flattened list from tail to head. By the time you assign node.right = prev for any given node, prev already points to a fully wired subtree. This avoids the classic mistake of overwriting node.right before you have finished traversing the right subtree.

Iterative with Stack

The iterative approach uses an explicit stack to simulate preorder traversal and rewire pointers on the fly. Push the root onto the stack. On each iteration, pop the top node. If that node has a right child, push it. If it has a left child, push it (left is pushed second so it is popped first). Then point the popped node's right to whatever is now at the top of the stack — the next node to be processed in preorder. Set the popped node's left to null.

This approach is intuitive if you already know how to do iterative preorder traversal. The stack maintains the correct traversal order, and at each step, you know exactly which node comes next because it is sitting at the top of the stack. Wiring node.right = stack.peek() (or checking if the stack is empty) handles all cases including leaf nodes and nodes with only one child.

The time complexity is O(n) since every node is pushed and popped exactly once. The space complexity is O(h) where h is the height of the tree — in the worst case a completely left-skewed tree — because the stack can hold at most one node per level of the right spine being built.

  1. 1Push root onto the stack
  2. 2While the stack is not empty: pop node from stack
  3. 3If node has a right child, push node.right onto stack
  4. 4If node has a left child, push node.left onto stack
  5. 5Set node.right = stack is empty ? null : stack top (the next preorder node)
  6. 6Set node.left = null
  7. 7Repeat until stack is empty

Morris Traversal — O(1) Space

Morris traversal achieves O(1) extra space by using the tree structure itself as temporary storage. For each node that has a left child, find the rightmost node in the left subtree — this is called the inorder predecessor. Connect that rightmost node's right pointer to the current node's right child. Then move the entire left subtree to the right: set node.right = node.left, set node.left = null. Advance to node.right and repeat.

The effect is that the left subtree is grafted onto the right side, and its rightmost leaf now connects to what was originally the right subtree. After this operation, the current node has no left child, and its right child is the root of the combined subtree in the correct preorder order. Repeating this for every node from root downward flattens the entire tree.

Morris traversal touches each node at most twice — once when it is the current node, and once when it is being visited as the rightmost predecessor during the search. This gives O(n) time complexity with O(1) space because no stack or recursion is used. The tree's own pointers serve as the traversal mechanism.

ℹ️

Morris Traversal Key Insight

Morris traversal rewires the tree as it goes, using the rightmost predecessor of the left subtree as a temporary bridge to the right subtree. By moving the entire left subtree to the right and wiring the predecessor to the old right child, the tree is flattened level by level without any auxiliary stack or recursion — achieving O(1) extra space.

Comparing the Three Approaches

All three approaches produce the same correct result and run in O(n) time. The difference is in space complexity and conceptual difficulty. Recursive reverse postorder is the most concise — typically 5–6 lines — and the easiest to explain once you internalize the "build from tail to head" insight. The iterative stack version is the most explicit about what preorder traversal is doing.

Morris traversal stands alone as the O(1) space solution. Its space advantage comes at the cost of being harder to read and verify. When an interviewer asks the O(1) follow-up, Morris traversal is the expected answer. Be prepared to explain why the rightmost predecessor search does not create an infinite loop — it terminates because you are looking only at the left subtree, which shrinks as the algorithm progresses.

In practice, recursive reverse postorder wins on code clarity, iterative wins on stack-overflow safety for extremely deep trees, and Morris wins on memory. For most LeetCode submissions, the recursive approach is the fastest to write correctly under time pressure.

  1. 1Recursive (reverse postorder): O(n) time, O(h) space (call stack), shortest code
  2. 2Iterative with stack: O(n) time, O(h) space (explicit stack), most readable traversal logic
  3. 3Morris traversal: O(n) time, O(1) space, most memory-efficient — best for O(1) follow-up
  4. 4All three set left pointers to null and right pointers to next preorder node
  5. 5For interviews: recursive for speed, Morris for the O(1) follow-up question

Code Walkthrough: Python and Java

In Python, the recursive solution uses a nonlocal prev variable initialized to None. The helper visits right, then left, then the current node: node.right = prev; node.left = None; prev = node. In Java, prev is an instance variable (TreeNode prev = null) since Java does not have nonlocal. Both are under 10 lines for the recursive core. The iterative stack solution in Python uses a deque: push root, loop while deque, pop, push right then left, set node.right = deque[0] if deque else None, set node.left = None.

The Morris traversal in Python: while node is not None, if node.left is not None, find rightmost = node.left, loop while rightmost.right is not None: rightmost = rightmost.right, then rightmost.right = node.right, node.right = node.left, node.left = None, then node = node.right. In Java the same logic with explicit null checks. This is the most interview-impressive version because O(1) space in a tree problem is unusual.

All three versions pass LeetCode 114 with identical accepted results. The recursive version is usually the first approach to reach; the Morris version is what you show after being asked the O(1) follow-up. Having both memorized as patterns — rather than derived from scratch — is the practical advantage in a timed interview setting.

⚠️

Recursive Order Bug

In the recursive approach, you MUST process right before left. If you process left first and assign node.right = prev (the flattened left subtree), you have permanently overwritten node.right before ever traversing the original right subtree. Processing right → left → root ensures node.right is read before it is overwritten.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now