← All Posts
DSA Series · Trees · Algorithms

Tree Interview Patterns

Most tree problems in interviews are variations of a handful of core patterns. Recognizing which pattern applies is half the battle. This post gives you the templates, the classic problems, and a cheat sheet for pattern recognition.

Pattern 1: Bottom-Up DFS (Post-Order)

When to use: When the answer for a node depends on answers from its children. Information flows upward.

Template:

Result solve(TreeNode* node) {
    if (!node) return BASE_CASE;
    auto leftResult  = solve(node->left);
    auto rightResult = solve(node->right);
    // Combine left + right + current node
    return combine(leftResult, rightResult, node->val);
}

Classic problems:

Pattern 2: Top-Down DFS (Pre-Order)

When to use: When you carry context downward from parent to children. Information flows from root toward leaves.

Template:

void solve(TreeNode* node, Context ctx) {
    if (!node) return;
    // Process current node with context from parent
    process(node, ctx);
    solve(node->left, updateContext(ctx, node));
    solve(node->right, updateContext(ctx, node));
}

Classic problems:

Pattern 3: BFS (Level-Order)

When to use: When the problem involves levels, layers, or finding the shortest path in an unweighted tree.

Template:

void levelOrder(TreeNode* root) {
    if (!root) return;
    std::queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        int levelSize = q.size();  // nodes at current level
        for (int i = 0; i < levelSize; i++) {
            auto* node = q.front(); q.pop();
            process(node);
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
    }
}

Classic problems:

Pattern 4: Construct from Traversals

When to use: Reconstruct a tree from serialization or from traversal orders.

Key facts:

// Build tree from preorder + inorder
TreeNode* build(vector<int>& pre, int preStart, int preEnd,
                vector<int>& in, int inStart, int inEnd,
                unordered_map<int,int>& inMap) {
    if (preStart > preEnd) return nullptr;
    int rootVal = pre[preStart];
    auto* root = new TreeNode(rootVal);
    int inIdx = inMap[rootVal];     // root's position in inorder
    int leftSize = inIdx - inStart; // nodes in left subtree
    root->left  = build(pre, preStart+1, preStart+leftSize,
                        in, inStart, inIdx-1, inMap);
    root->right = build(pre, preStart+leftSize+1, preEnd,
                        in, inIdx+1, inEnd, inMap);
    return root;
}

Pattern 5: BST-Specific Tricks

When to use: When the problem gives you a BST (or you can exploit sorted order).

How to Recognize the Pattern

If the problem says...Think...
"height", "depth", "balanced", "diameter"Bottom-up DFS (pattern 1)
"path from root", "sum along path", "validate"Top-down DFS (pattern 2)
"level", "layer", "zigzag", "right view", "minimum depth"BFS (pattern 3)
"construct", "rebuild", "from array"Build/divide (pattern 4)
"BST", "kth", "range", "sorted"BST property (pattern 5)
"O(1) space traversal"Morris traversal

Summary