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.
- 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
root = [3,9,20,null,null,15,7]3root = [1,null,2]2root = [1,2,3,4,null,null,null,5]4root = []0The 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.
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.
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.
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.
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 reportedmax, 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.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.
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.
Maximum Depth Audit
Recursive Height Reporting
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"