← All patterns
Tree DFS
Recursive depth-first traversal. Pre / in / post-order, path-sum aggregation, LCA, height, diameter, serialization, BST validation — most tree questions reduce to a single DFS with carefully chosen return values.
21 problems
7 Easy 9 Medium 5 Hard
Recursive depth-first traversal of binary trees. The strategic question is always: what does each recursive call *return*? Often a tuple (height + best-path, rob + skip, count + sum) so the parent can combine without re-DFSing.
Pre/in/post-order each have a natural fit: in-order for BSTs (yields sorted), post-order for bottom-up aggregations (height, diameter), pre-order for path reconstruction.
When to reach for this pattern
- Binary tree input with no parent pointer
- Per-node computation depending on subtree information
- Path-based questions (path sum, longest path, diameter)
- Tree validation (BST, balanced, symmetric)
Canonical template
// post-order combine pattern
int dfs(TreeNode* n) {
if (!n) return 0;
int l = dfs(n->left), r = dfs(n->right);
// combine l, r, and n->val into this node's contribution
return ...;
}
// tuple-return for two-state DP per node
pair<int, int> dfs(TreeNode* n) {
if (!n) return {0, 0};
auto [lRob, lSkip] = dfs(n->left);
auto [rRob, rSkip] = dfs(n->right);
int rob = n->val + lSkip + rSkip;
int skip = max(lRob, lSkip) + max(rRob, rSkip);
return {rob, skip};
} C++ · adapt the names and types to your problem.
Common pitfalls
- Forgetting to handle the null-node base case
- Updating a 'best' global from inside DFS but returning a *different* quantity — easy to mix up
- BST validation: compare against an ancestor range, not just the direct parent
- Recursion depth on skewed trees can hit stack limits; iterative DFS via explicit stack avoids it
Related patterns
Problems (21)
- Hard
- Easy
- Hard
- Medium
- Medium
- Medium
- Easy
- Medium
- Medium
- Easy
- Easy
- Medium
- Medium
- Medium
- Hard
- Medium
- Hard
- Hard
- Easy
- Easy
- Easy