Maximum Depth of Binary Tree
A node's depth is one more than its deeper subtree.
Approach
Recurse: the depth of a node is 1 + max(depth(left), depth(right)), with null contributing 0. A BFS level count works too. Both visit every node once.
Time complexity
O(n)
Space complexity
O(h)
Common mistake
Off-by-one at the base case — a null child is depth 0, a leaf is depth 1.
Interactive walkthrough — step through it below, free and without an account
Problem
Given the root of a binary tree, determine how many nodes appear on the longest path from the root down to any leaf. Return 0 when the tree is empty. You may solve this by recursively combining subtree depths or by counting the levels visited in a breadth-first traversal.
Examples
Input: root = [3,9,20,null,null,15,7]
Output: 3
Input: root = [1,null,2]
Output: 2
Problem
Problem
Given the root of a binary tree, determine how many nodes appear on the longest path from the root down to any leaf. Return 0 when the tree is empty. You may solve this by recursively combining subtree depths or by counting the levels visited in a breadth-first traversal.
Problem and Goal
Learning goal: Recognize maximum depth as the length of the longest root-to-leaf path.
Core idea
Depth counts nodes, not edges. An empty tree has depth 0; a tree containing only its root has depth 1. For a larger tree, the answer is determined by whichever child subtree reaches farther from the current node.
Definition
The depth of a tree is the number of nodes on its longest path from the root to a leaf.
Algorithm plan
- Start at the root.
- Explore both the left and right subtrees.
- Keep the larger subtree depth.
- Add
1for the current node.
Micro-example
For 3 → 20 → 15, the path contains three nodes, so its depth is 3.
For an empty child such as the left child of 9, the depth is 0.
Pitfalls
- Counting edges instead of nodes produces an answer that is one too small.
- Forgetting the empty-tree case makes
root = nullfail. - Only following one child misses a deeper path on the other side.
Recap
- Depth is a longest-path measurement.
- A leaf has depth
1. - The empty tree has depth
0.
Problem and Goal
Count nodes on the longest root-to-leaf path
For [3,9,20,null,null,15,7], the longest path contains 3 → 20 → 15 or 3 → 20 → 7.
Leaf = depth 1; null = depth 0.
The Recursive Insight
Learning goal: Derive the recurrence that turns a tree problem into smaller subtree problems.
Core idea Once we know the depth of the left and right subtrees, the current node contributes exactly one additional level. Therefore, the deeper subtree determines the answer below this node, and the current node is added afterward.
Key insight
A node's depth is one more than the depth of its deeper subtree.
Recurrence
depth(node) = 0 when node is null.
depth(node) = 1 + max(depth(node.left), depth(node.right)) otherwise.
| Situation | Result | Reason |
|---|---|---|
node == null | 0 | No node contributes a level |
| Leaf node | 1 | Both child depths are 0 |
| Internal node | 1 + max(left, right) | Keep the deeper branch |
Algorithm plan
maxDepth(node):
if node is null:
return 0
leftDepth = maxDepth(node.left)
rightDepth = maxDepth(node.right)
return 1 + max(leftDepth, rightDepth)Micro-example
For node 20, the subtree rooted at 15 has depth 1, and the subtree rooted at 7 has depth 1.
Thus depth(20) = 1 + max(1, 1) = 2.
Pitfalls
- Applying
1 + max(...)tonullwould make empty children incorrectly contribute a level. - Returning
max(left, right)without the1omits the current node. - The recursive calls must explore both children.
Recap
- Solve two smaller instances, then combine them.
nullcontributes0.- The current node contributes
1.
The Recursive Insight
Use the deeper child and add the current node.
1 + max(leftDepth, rightDepth)
DFS and BFS Approaches
Learning goal: Compare recursive DFS with level-order BFS and understand why both are linear-time traversals.
Core idea Recursive DFS computes a numerical answer while returning from each subtree. BFS instead processes the tree one level at a time; after finishing one queue layer, it increments a level counter. Both approaches must inspect every reachable node because any node could extend the deepest path.
Algorithm plan
- DFS: Define the recurrence, recurse on both children, and combine returned depths.
- BFS: Put the root in a queue, process all nodes currently in the queue, enqueue their children, and increment the level count after each layer.
- Choose DFS when the recurrence is the clearest expression of the problem.
- Choose BFS when level boundaries or minimum distance are central to the task.
| Approach | Time | Extra space | Main state |
|---|---|---|---|
| Recursive DFS | O(n) | O(h) | Call stack follows a root-to-leaf path |
| Level-order BFS | O(n) | O(w) | Queue holds one or more levels |
Here, n is the number of nodes, h is the tree height, and w is the maximum width. For this lesson, the recursive DFS is the main implementation and h is the target auxiliary-space measure.
Micro-example
DFS visits 3, explores 9, then explores 20 and its children before combining results.
BFS would process [3], then [9,20], then [15,7], producing three levels.
Pitfalls
- Calling BFS space
O(h)in every tree shape is inaccurate; its queue isO(w). - A recursive implementation uses stack space even though it does not allocate a separate queue.
- Traversal order changes, but the final depth does not.
Recap
- DFS follows the recurrence directly.
- BFS counts completed levels.
- Both visit each node once.
DFS and BFS Approaches
| Approach | Core operation | Time | Extra space |
|---|---|---|---|
| Recursive DFS | Return 1 + max(left, right) | O(n) | O(h) |
| BFS | Count queue levels | O(n) | O(w) |
Walkthrough: Recursive DFS
Learning goal: Trace how subtree answers return upward to produce the final depth.
Core idea
Use the example root = [3,9,20,null,null,15,7]. DFS first reaches the leaves, where each leaf returns 1. Those values then flow upward: node 20 receives two child depths of 1 and returns 2, while node 3 receives 1 and 2 and returns 3.
- Enter a node and recursively solve its left subtree.
- Recursively solve its right subtree.
- Take the larger returned depth.
- Add
1for the node itself and return upward.
Worked calculation
def maxDepth(node):
if node is None:
return 0
return 1 + max(maxDepth(node.left), maxDepth(node.right))For node 9, both children are null, so depth(9) = 1 + max(0, 0) = 1. For node 20, both children are leaves, so depth(20) = 1 + max(1, 1) = 2. Finally, depth(3) = 1 + max(1, 2) = 3.
Why it works
Every node returns the correct depth for its subtree before its parent combines that result with the other child.
Pitfalls
- Do not combine node
20before both child calls return. - The final answer is the value returned by the root, not the number of recursive calls.
- A null child is a valid completed subproblem.
Recap
- Leaves return
1. - Results are combined during the return phase.
- The root returns the complete tree depth.
Walkthrough: Recursive DFS
Animate the recursive DFS on the same example from the first call to the final return.
Pitfalls and Edge Cases
Learning goal: Guard against the base-case and counting mistakes that most often break this solution.
Core idea
The recurrence is short, but its base case defines the meaning of every returned value. A null pointer represents no node and therefore contributes 0; a leaf has two null children, so it returns 1. This convention makes the recurrence work uniformly for every non-null node.
Edge-case checklist
- Empty tree:
maxDepth(null) = 0. - Single node: both children are null, so the answer is
1. - One-sided chain: every node adds one, producing the chain length.
- Balanced tree: compare both branches at every internal node.
Common pitfall
Off-by-one errors happen when null is treated as depth 1 or when a leaf is treated as depth 0. Use null = 0 and leaf = 1 consistently.
Micro-example
For [1,null,2], node 2 returns 1. Then node 1 returns 1 + max(0, 1) = 2, not 1.
Pitfalls
- Returning
0for a leaf confuses a node with an empty child. - Returning
1for null makes every path too deep. - Testing only balanced trees can hide errors on skewed trees.
- A very deep skewed tree can approach recursion depth limits in some languages.
Recap
- Null means no level:
0. - A leaf is one level:
1. - Test empty, single-node, and one-sided trees.
Pitfalls and Edge Cases
For a leaf node whose left and right children are both null, what depth should the recursive formula return?
Complexity and Wrap-up
Learning goal: Justify the performance of the recursive traversal and summarize the reusable pattern.
Core idea
Each node is entered once and its two child references are examined once. The work therefore grows linearly with the number of nodes. The recursion stack stores the active path from the root to the current node, so its auxiliary space is proportional to the tree height h.
Complexity
| Measure | Bound | Explanation |
|---|---|---|
| Time | O(n) | Every node is visited once |
| Space | O(h) | The call stack holds one root-to-current path |
For a balanced tree, h is about log n. For a completely skewed tree, h can be n. BFS also takes O(n) time, but its queue uses O(w) space, where w is the maximum width.
Why it works
The recurrence is correct at null children, leaves, and internal nodes; induction over the tree then makes the root's returned value correct.
Micro-example
The example has five nodes, and DFS visits all five exactly once. Its deepest active path has three nodes, so the recursion uses O(h) space with h = 3.
Pitfalls
- Do not claim constant space for recursive DFS.
- Do not confuse height
hwith the number of nodesn. - BFS and DFS share time complexity, but not always auxiliary-space complexity.
Recap
- Recurrence:
1 + max(left, right). - Base case: null contributes
0. - Performance:
O(n)time andO(h)recursive space.
Complexity and Wrap-up
Summarize the cost of recursive DFS for maximum depth.
Now try it on your own problem
Paste any LeetCode problem — or one of your own — and codebrew builds a walkthrough like this one for it.
Build a lesson from any problem
