Maximum Depth of Binary Tree — Recursive DFS, Iterative DFS & BFS
| LeetCode #104 | Difficulty: Easy |
Intuition
The maximum depth of a binary tree is the number of nodes along the longest path from the root to a leaf.
For any node: depth = 1 + max(depth of left subtree, depth of right subtree)
This naturally suggests a Depth First Search solution. However, the problem can also be solved using:
- Recursive DFS
- Iterative DFS (using stack)
- Iterative BFS (level order traversal)
Approach 1: Recursive DFS
- Base Case
- If the node is
nullptr, its depth is 0.
- If the node is
- Recursive Case
- Recursively compute:
- Depth of left subtree.
- Depth of right subtree.
-
Return:
1 + max(leftDepth, rightDepth)
- Recursively compute:
- The recursion naturally traverses the entire tree in a Depth-First manner, computing height bottom-up.
This is a classic example of postorder DFS where we compute results from children before returning to the parent.
Complexity
-
Time complexity: O(n)
Each node is visited exactly once.
-
Space complexity: O(h)
Where
his the height of the tree. In the worst case (skewed tree), this becomes O(n). In a balanced tree, it is O(log n).
Code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
};
Approach 2: Iterative DFS (Using Stack)
Instead of recursion, we simulate DFS using a stack.
Store: pair<TreeNode*, depth>
Process nodes and keep track of maximum depth.
Complexity
- Time complexity: O(n)
- Space complexity: O(h)
Code
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
stack<pair<TreeNode*, int>> nodeStack;
int maxDepth = 0, depth;
nodeStack.push({root, 1});
while(!nodeStack.empty()) {
TreeNode *node = nodeStack.top().first;
depth = nodeStack.top().second;
nodeStack.pop();
maxDepth = max(maxDepth, depth);
if(node->left) nodeStack.push({node->left, depth + 1});
if(node->right) nodeStack.push({node->right, depth + 1});
}
return maxDepth;
}
};
Approach 3: Iterative BFS (Level Order Traversal)
We traverse the tree level by level. Each level increases the depth by 1.
Use a queue:
- Push root.
- For each level:
- Process all nodes at that level.
- Increment depth.
Complexity
- Time complexity: O(n)
- Space complexity: O(w) (w = maximum width of tree)
Code
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
queue<pair<TreeNode*, int>> nodeQ;
int maxDepth = 0, depth;
nodeQ.push({root, 1});
while(!nodeQ.empty()) {
TreeNode *node = nodeQ.front().first;
depth = nodeQ.front().second;
nodeQ.pop();
maxDepth = max(maxDepth, depth);
if(node->left) nodeQ.push({node->left, depth + 1});
if(node->right) nodeQ.push({node->right, depth + 1});
}
return maxDepth;
}
};
Summary
| Approach | Time | Space | Notes |
|---|---|---|---|
| Recursive DFS | O(n) | O(h) | Clean & most common |
| Iterative DFS | O(n) | O(h) | Avoids recursion |
| BFS | O(n) | O(w) | Natural level counting |
All three approaches are optimal in time complexity.