Skip to content
ΣDSA Patterns
Menu
Language

Pattern #16

Tree DFS

Essential

Define what each subtree returns to its parent.

When to use

Binary tree answers that combine left and right results: depth, validity, LCA, path sums.

Recognition cues

  • Max depth / balanced tree
  • Validate BST / LCA
  • Path sum variants

Common pitfalls

  • Mixing global answer updates with return values carelessly
  • BST validation with wrong bounds
  • Not handling null children as base case

90-second recognition drill

Which pattern fits best?

  • Max depth / balanced tree
  • Validate BST / LCA
  • Path sum variants

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 8
3920157

post-order: children first, then me

Tree DFS walks structure, not a flat list. Root 3, left 9, right subtree 20 → 15, 7.

How to think about it

Write a function f(node) that returns what the parent needs (height, is-BST flag, min/max, best path through node). Solve left and right first, then combine. Sometimes also update a global best.

The interactive mental model draws the actual tree (edges + nodes), not a flat list: watch values and badges (heights, LCA markers) flow up the structure.

Template shapes

Shape Core move Notes
Return height 1+max(L,R) Depth, balance
Return multi-field struct of flags BST / diameter
Pass bounds low < val < high Validate BST

Complexity baseline

O(n) time visits each node once; space O(h) recursion stack.

From template to problem

  1. Specify f(node)’s return type in one sentence.
  2. Base case for null.
  3. Recurse left/right; combine; optionally update global answer.
  4. Return the value the parent requires.

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Tree DFS · Template
/** Tree DFS template: max depth. */
export class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val; this.left = left; this.right = right;
  }
}
export function maxDepth(root: TreeNode | null): number {
  if (!root) return 0;
  return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
/** Tree DFS template: max depth. */
export class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val; this.left = left; this.right = right;
  }
}
export function maxDepth(root: TreeNode | null): number {
  if (!root) return 0;
  return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}