The 5 Questions I Ask Before Writing Any Bottom-Up Tree DFS

Python | The 5 Questions I Ask Before Writing Any Bottom-Up Tree DFS

One of the biggest struggles with tree recursion isn't writing the code—it's knowing how to think about the recursion in the first place.

Whenever I see a tree DFS problem, I don't try to memorize the solution.

Instead, I ask these 5 questions.


1. What's my base case?

Every recursion needs a stopping condition.

Ask yourself:

What should I return if there is no node?

if not node:
    return ...

The return value depends on the problem.

Examples:

Maximum Depth      -> 0
LCA                -> None
Balanced Tree      -> 0
Path Sum           -> False

2. Can I answer immediately myself? (Self Case)

Before asking my children anything, I ask:

Can I solve the problem at the current node without looking below?

If yes, return immediately.

Example (LCA):

if node == p or node == q:
    return node

Example (Path Sum):

if not node.left and not node.right:
    return target == node.val

Some problems don't have a self case at all.


3. What should I ask my children?

If I cannot answer yet, I need information from my children.

left = dfs(node.left)
right = dfs(node.right)

Think of it like asking:

Left child,
what did you find?

Right child,
what did you find?

Notice that nothing has been solved yet.

We're simply collecting information.


4. How do I combine my children's answers?

Now I'm the parent.

Both children have answered.

I combine their answers to solve my own subproblem.

Example: Maximum Depth

Children return:

height

So I combine them using:

return 1 + max(left, right)

Example: Lowest Common Ancestor

Children return:

None
p
q
LCA

So I combine them like this:

if left and right:
    return node

Example: Diameter of Binary Tree

Children return:

height

Parent updates:

diameter = max(diameter, left + right)

Every tree problem has a different combine step.


5. What should I return to my parent?

Finally ask:

What information does my parent need from me?

This is the most important question.

Examples:

Maximum Depth

return 1 + max(left, right)

Balanced Tree

return height

Lowest Common Ancestor

return left or right

Every recursive call is returning information upward.

That's why this is called bottom-up DFS.


General Bottom-Up DFS Template

def dfs(node):

    # 1. Base case
    if not node:
        return ...

    # 2. Self case
    if ...:
        return ...

    # 3. Ask children
    left = dfs(node.left)
    right = dfs(node.right)

    # 4. Combine children's answers
    ...

    # 5. Return information to parent
    return ...

How Do I Know It's Bottom-Up?

Ask yourself one question:

Can the parent solve the problem before the children finish?

If No, it's probably bottom-up DFS.

The parent must wait for information from the children before making its own decision.


Common Bottom-Up Tree Problems

ProblemChildren ReturnParent Combines
Maximum DepthHeight1 + max(left, right)
Diameter of Binary TreeHeightUpdate diameter = left + right
Balanced Binary TreeHeightCheck abs(left - right)
Lowest Common AncestorNone, p, q, or LCAIf both sides return non-null, current node is LCA
Binary Tree Maximum Path SumMaximum gainUpdate global maximum path

Notice that the template stays the same.

Only these two parts change:

  • What information should each child return?
  • How should the parent combine those answers?

The Biggest Mindset Shift

Don't think:

"How do I solve the whole problem?"

Instead think:

"What information should each node return to its parent?"

Once you know what every recursive call should return, the DFS almost writes itself.

That's the mental model that helped recursion finally click for me, and I hope it helps someone else too.

Comments (1)