Algorithm

Maximum Depth of Binary Tree

Trees Pattern

Maximum Depth of Binary Tree

Given the root of a binary tree, return its maximum depth: the number of nodes along the longest downward path from the root to any leaf. A leaf is a node with no children. By this counting, a single node has depth 1, and an empty tree has depth 0.

CONSTRAINTS
  • The number of nodes in the tree is in the range [0, 10⁴]
  • -100 <= Node.val <= 100
  • Depth is measured in nodes, not edges
  • The tree may be a single chain, so the depth can equal the node count
EXAMPLE 1
Input: root = [3,9,20,null,null,15,7]
Output: 3
The longest root-to-leaf path is 3, 20, 15 (or equally 3, 20, 7) and contains 3 nodes. The path 3, 9 is shorter, and a shorter path never lowers the answer — only the deepest one counts.
EXAMPLE 2
Input: root = [1,null,2]
Output: 2
1 has no left child at all, so the only path down is 1 then 2. The missing side contributes nothing rather than counting as a level.
EXAMPLE 3
Input: root = [1,2,3,4,null,null,null,5]
Output: 4
The path 1, 2, 4, 5 has 4 nodes while 1, 3 has only 2. The tree is lopsided, which is allowed — nothing requires the two sides to be similar in size.
EXAMPLE 4
Input: root = []
Output: 0
There are no nodes on any path, so the count is zero. This is the value that makes the counting consistent, not a special error case.
Is depth counted in nodes or in edges?
Nodes here, so a lone node has depth 1 and an empty tree has depth 0. Always confirm this — the edge convention gives answers exactly one smaller, and the off-by-one is the most common way to fail this problem.
Does the path have to end at a leaf?
Effectively yes: stopping early can only produce a shorter count, so the longest path always runs all the way down to a leaf.
Can the tree be badly unbalanced?
Yes. Nothing here promises balance, so with 10⁴ nodes in one chain the recursion could go 10⁴ frames deep — worth raising if the interviewer cares about stack limits.
Do negative values affect the depth?
No. Depth is purely structural; the values are never read. That distinguishes it from Path Sum, where the values are the whole point.

The depth of a tree is how many nodes you pass through on the longest route from the root straight down to a leaf. Nothing in that definition mentions values — this is a question about shape alone.

A first instinct is to enumerate every root-to-leaf path, count the nodes in each, and keep the largest. That works, and it is worth noticing why we can do better: those paths overlap enormously. Two leaves sharing a grandparent share the entire route above that grandparent, and re-walking the shared portion once per leaf is wasted effort. There is a way to count each node exactly once instead.

The question a node can actually answer

Stand on some node in the middle of the tree. You cannot see the root, and you have no idea how far below the root you are — so you cannot compute the final answer. But you can answer a smaller, purely local question: how deep is the tree that starts here?

And you can answer it if your two children answer it first. Every downward path from you begins by stepping into the left child or the right child, and then continues as a path within that child's subtree. So the longest path starting at you is: yourself, plus the longer of the two answers your children report.

text
depth(node) = 1 + max( depth(node.left), depth(node.right) )

The base case falls out of the same formula rather than being bolted on. An empty tree has no nodes on any path, so depth(null) = 0. Check it against a leaf: both its children are null and report 0, so the leaf returns 1 + max(0, 0) = 1 — correct, a leaf on its own is one node deep. The convention is consistent, which is the sign you picked the right base value.

Why the work must happen after the calls

This is the first problem where the traversal order is forced, so it is worth naming what forces it. A node's answer is a function of its children's answers. It literally cannot be computed on arrival — at that moment nothing is known about what lies below. So the node must launch both recursive calls, wait, and only then combine. Work after both children is the post-order slot, and information travelling upward like this is what post-order is.

Contrast that with Invert Binary Tree, where the swap needed nothing from below and could happen at any moment. The rule generalizes cleanly: if what a node must do depends on results from beneath it, the recursion returns a value and you combine after the calls; if it depends on context from above, you pass a value down as an argument instead. Nearly every tree problem in this section is one of those two shapes, and Sum Root to Leaf Numbers will demonstrate the other one.

python
def maxDepth(node):
    if node is None:
        return 0                       # empty tree contributes no nodes
    left  = maxDepth(node.left)        # ask below, and wait
    right = maxDepth(node.right)
    return 1 + max(left, right)        # combine only after both have reported
Crucial Noteit is max, not left + right, and not min. A single path goes down one side or the other; it cannot use both. Adding the two would count a path that bends through the node and back down — that is a genuinely different quantity, and it is exactly the one Diameter of Binary Tree asks for. Using min answers a different question again, the shallowest leaf. Three one-word variations, three distinct problems: the combining step is where a tree problem's real identity lives.
Worked example:root 3, with children 9 and 20; 20 has children 15 and 7
- The call on 9: both children are null and return 0, so 9 returns 1 + max(0, 0) = 1.
- The call on 15: same shape, returns 1. Likewise 7 returns 1.
- The call on 20 now has both reports in hand: 1 + max(1, 1) = 2.
- The root 3 waits for 9 (1) and 20 (2), then returns 1 + max(1, 2) = 3.

The root never inspected 15 or 7 itself. It trusted 20's single summarising number, which is precisely how the overlapping-path waste disappears: each node hands its parent one integer instead of a list of paths.

Cost, and the alternative

Every node is entered once and does constant work there, so the time is O(N) — and that is optimal, since the deepest leaf could be anywhere and skipping a node risks missing it. Extra space is the recursion stack, O(H): about log₂N on a balanced tree, but N on a chain, which with 10⁴ nodes is enough to make an interviewer ask about stack overflow.

The answer to that concern is to walk the tree level by level with a queue instead — process all nodes at one depth, collect their children as the next level, and count how many levels you consumed. That is breadth-first search, developed properly in Binary Tree Level Order Traversal; it also runs in O(N) time but its memory is the widest level rather than the height, so it is the safer choice on deep chains and the worse one on wide, bushy trees.

Carry forward the framing rather than the formula: a tree recursion is defined by three decisions — what the base case returns, what one node computes from its children's answers, and what it reports upward. Here those are 0, one max and a +1, and the depth itself. Balanced Binary Tree keeps this exact function and adds a verdict to what gets reported; Diameter keeps it and tracks a second quantity on the side. Once you see this skeleton, that whole family stops looking like separate problems.

Interactive Strategy Visualization

Maximum Depth Audit

Recursive Height Reporting

1235
Explore Root (1). Moving Left.
Recursive Buffer
Result for Current Call
?

Height of a node is 1 + maximum of its children's heights.

"Base Case: Return 0 when node is null."

Strategy

Post-order DFS is natural here: we cannot know a parent's height until we know its children's.

"H = max(L, R) + 1"

O(N) Time · O(H) Space Post-order Recursion
O(N) Time · O(W) Space Level-by-Level BFS