Maximum Depth of a Binary Tree is the classic warm-up for tree recursion. It teaches the single most useful idea for trees: a tree problem is almost always a smaller version of itself on each child, solved by DFS recursion.
Problem. Given the root of a binary tree, return its maximum depth — the number of nodes along the longest path from the root down to the farthest leaf.
Example: the tree 3 → (9, 20 → (15, 7)) has depth 3 (the path 3 → 20 → 15 is three nodes long).
The idea
A tree is recursive by nature: every node is itself the root of a smaller subtree. So instead of trying to measure the whole tree at once, ask one small question at each node:
How deep is the subtree that starts here?
The answer is simple. An empty tree (a null child) has depth 0. Any real node is 1 (for itself) plus the depth of its deeper child:
depth(node) = 1 + max(depth(left), depth(right))That is the whole algorithm. We walk down with recursion until we hit null, then the answers bubble back up: each leaf returns 1, its parent takes the max of its children and adds 1, and so on until the root returns the full depth.
There is no faster approach — we must look at every node once to know it exists — so this clean O(n) recursion is the intended answer.
Walk through it
Step through the animation. The highlight moves down the tree as we call maxDepth on each node (3 → 9, then 3 → 20 → 15, then 20 → 7). When a node finishes, its returned depth appears as a badge and the node turns green. Watch the depths bubble back up: leaves return 1, node 20 returns 2, and the root returns 3.
Pseudocode
function maxDepth(node):
if node is null:
return 0 # empty tree has no depth
leftDepth = maxDepth(node.left) # recurse down the left
rightDepth = maxDepth(node.right) # recurse down the right
return 1 + max(leftDepth, rightDepth) # this node + deeper sideThe base case (null → 0) is what stops the recursion. Every other call leans on the answers from its two children.
The Python solution
def max_depth(root):
if root is None:
return 0
left = max_depth(root.left)
right = max_depth(root.right)
return 1 + max(left, right)- Lines 2–3 are the base case: a
Nonenode contributes0depth and stops the recursion. left = max_depth(root.left)recurses all the way down the left subtree before doing anything else.right = max_depth(root.right)then does the same for the right subtree.- Line 6 combines them:
1for the current node plus the depth of its deeper child. This return value is what the parent call receives.
Complexity
| Case | Time | Notes |
|---|---|---|
| Visit every node (DFS) | O(n) (moderate) | each node is touched exactly once |
O(h) (moderate)Time is O(n) because we visit all n nodes once. The extra space is O(h), the height of the tree — that is the depth of the recursion call stack. For a balanced tree that is O(log n); for a degenerate (linked-list-shaped) tree it is O(n).
When this pattern shows up
Most binary-tree questions are solved by the same move: recurse on the children, then combine their
results. Maximum depth, "same tree," "symmetric tree," "count nodes," and "diameter" are all the same
shape — define what a node returns, handle the null base case, and combine the two child answers.
Do not forget the base case. If you skip the if root is None: return 0 check, the recursion calls
.left on None and crashes. The empty-tree case is what makes the recursion terminate.
Practice
In the example tree, node 20 has two leaf children (15 and 7) that each return 1. What does maxDepth(20) return, and why?
1. What does maxDepth return for a null node?
2. How does a node compute its own depth?
3. Why is the time complexity O(n)?
4. What determines the extra space used by the recursion?