Trees
Trees are hierarchical structures. Many problems are naturally recursive and revolve around how information flows through the tree.
1. Traversals (The "Vocabulary")
Before solving tree problems, you must be comfortable with the standard traversals. Each visits nodes in a different order:
- Preorder (DFS): Root -> Left -> Right. Used for copying trees or prefix expressions.
- Inorder (DFS): Left -> Root -> Right. Crucial for BSTs (yields sorted order).
- Postorder (DFS): Left -> Right -> Root. Used for deleting trees or aggregating info from children (e.g., height).
- Level-Order (BFS): Row by row. Used for finding shortest paths in unweighted graphs.
2. Thinking Recursively: The Information Flow
Most tree problems boil down to one question: What information needs to flow where?
- Down the tree (Parameters): Pass values from parent to child.
- Examples:
current_depth,max_value_so_far,target_sum_remaining.
- Examples:
- Up the tree (Return Values): Pass values from child to parent.
- Examples:
subtree_height,is_balanced,max_path_sum_in_subtree.
- Examples:
- Global State: Update a variable outside the recursion.
- Examples:
max_diameter,result_list.
- Examples:
3. Tree Properties & Types
Not all binary trees are created equal. The structure determines the runtime.
- Perfect: Every level is completely filled. Count = .
- Complete: Filled except possibly the last level (nodes aligned left). Heaps are complete trees.
- Balanced: Height is . Operations are fast.
- Skewed: Height is . Operations degrade to linked list performance.
4. Common Techniques & Recipes
The "Node-Depth Queue" (Iterative BFS)
When solving level-order problems iteratively, store pairs of (node, depth) in your queue.
queue = deque([(root, 0)])
while queue:
node, depth = queue.popleft()
# process node at depth
if node.left: queue.append((node.left, depth + 1))
if node.right: queue.append((node.right, depth + 1))
The "Parallel Pointers" Strategy For problems involving two trees (e.g., merging, comparing), iterate through both simultaneously.
- If both are BSTs, you can use iterative inorder traversals to treat them like sorted arrays (see Merge Two BSTs).
- If checking for equality, traverse both structure-wise in lockstep.
Practice Problems
Maximum Depth of Binary Tree
Practice this problem with interactive visualization.
Invert Binary Tree
Practice this problem with interactive visualization.
Validate Binary Search Tree
Practice this problem with interactive visualization.
Convert BST to Greater Tree
Practice this problem with interactive visualization.
Kth Smallest in BST
Practice this problem with interactive visualization.
Merge Two BSTs into Array
Practice this problem with interactive visualization.
Closest Value in BST
Practice this problem with interactive visualization.