Tree DFS (In/Pre/Post)
The Intuition
Tree DFS visits every node by recursively descending one branch fully before backtracking to the next. Three traversal orderings differ only in when the current node is processed relative to its subtrees:
- Preorder (root, left, right): process the node, then recurse left, then right. Used for serialization, copying a tree, and producing prefix expressions.
- Inorder (left, root, right): recurse left, process the node, recurse right. On a BST this produces values in sorted order, which is why inorder is the standard tool for BST validation (LC 98) and finding the kth smallest element (LC 230).
- Postorder (left, right, root): recurse left, recurse right, process the node. Used when subtree results must be combined, such as computing subtree sums, deleting a tree, or evaluating postfix expressions.
The recursion stack handles backtracking implicitly: every recursive call pushes a frame, every return pops one. Total time is O(n) for any traversal; space is O(h) for the recursion stack, where h is tree height (O(log n) balanced, O(n) worst case).
A common DFS pattern in interviews is the post-order with subtree return value. The recursive call returns information about the subtree (height, size, max path sum, whether it's balanced), and the parent combines its children's returns to compute its own answer. This pattern solves diameter (LC 543), max path sum (LC 124), is balanced (LC 110), and many subtree-size problems. The function typically returns one value to its parent while side-effectfully updating a global best variable when a subtree-internal answer is better than any seen so far.
Iterative implementations use an explicit stack. Iterative inorder is the trickiest: push nodes while descending left, pop to visit and emit, then descend right from the popped node's right child. The recursion-based code is almost always shorter and clearer, so prefer it unless stack-depth is a real concern.
Serialization, expression evaluation, BST validation, tree construction from traversals, path sum problems, or any tree problem requiring recursive decomposition.
- Need shortest path in a tree (use BFS)
- Need level-order information
- Tree is extremely deep and might overflow the call stack (use iterative BFS)
- empty tree
- single node
- skewed tree
Key Points
- •Pre-order: process node BEFORE children (root-left-right)
- •In-order: process node BETWEEN children (left-root-right). Gives sorted order in BST
- •Post-order: process node AFTER children (left-right-root)
- •Recursive approach mirrors the traversal naturally
- •Space is O(h) where h = tree height; O(log n) balanced, O(n) worst case
Code Template
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def preorder(root):
"""Pre-order: root -> left -> right."""
if not root:
return []
return [root.val] + preorder(root.left) + preorder(root.right)
def inorder(root):
"""In-order: left -> root -> right (sorted for BST)."""
if not root:
return []
return inorder(root.left) + [root.val] + inorder(root.right)
def postorder(root):
"""Post-order: left -> right -> root."""
if not root:
return []
return postorder(root.left) + postorder(root.right) + [root.val]
# Iterative in-order using stack
def inorder_iterative(root):
result, stack = [], []
current = root
while current or stack:
while current:
stack.append(current)
current = current.left
current = stack.pop()
result.append(current.val)
current = current.right
return resultCommon Mistakes
- Confusing pre/in/post ordering for specific problems
- Not handling the null/None base case
- Forgetting that in-order on BST gives sorted output