Skip to content

133. Maximum Depth of Binary Tree

🔗 LeetCode Problem: 104. Maximum Depth of Binary Tree
📊 Difficulty: Easy
🏷️ Topics: Binary Trees, Recursion, DFS, BFS, Tree Depth

Problem Statement

Given the root of a binary tree, return its maximum depth.

A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

Example 1:

Input: root = [3,9,20,null,null,15,7]
Output: 3

Example 2:

Input: root = [1,null,2]
Output: 2

Constraints: - The number of nodes in the tree is in the range [0, 10^4] - -100 <= Node.val <= 100


🌳 Visual Understanding - Drawing the Trees First!

What is "Depth" or "Height"?

Depth/Height = Number of nodes from root to farthest leaf

Count includes BOTH the root and the leaf!

Example:
       3          ← Level 1 (depth = 1)
      / \
     9   20      ← Level 2 (depth = 2)
        /  \
       15   7    ← Level 3 (depth = 3)

Maximum depth = 3 nodes
(Path: 3 → 20 → 15 or 3 → 20 → 7)

Example 1: Tree with Depth 3

Input: [3,9,20,null,null,15,7]

Visual Tree:
       3          ← Node at depth 1
      / \
     9   20      ← Nodes at depth 2
        /  \
       15   7    ← Nodes at depth 3

Paths from root to leaves:
  Path 1: 3 → 9 (length 2)
  Path 2: 3 → 20 → 15 (length 3) ✓ Longest!
  Path 3: 3 → 20 → 7 (length 3) ✓ Longest!

Maximum depth = 3

Example 2: Tree with Depth 2

Input: [1,null,2]

Visual Tree:
       1          ← Node at depth 1
        \
         2        ← Node at depth 2

Only one path: 1 → 2 (length 2)

Maximum depth = 2

Edge Cases to Consider:

Case 1: Empty tree
    root = null
    Depth = 0 (no nodes!)

Case 2: Single node
       5
    Depth = 1 (just the root)

Case 3: Left-skewed tree
       1
      /
     2
    /
   3
  /
 4
    Depth = 4

Case 4: Perfect binary tree
         1
        / \
       2   3
      / \  / \
     4  5 6  7
    Depth = 3

Case 5: All left children null
       1
        \
         2
          \
           3
    Depth = 3

🧠 The AHA Moment - Recursive Insight!

The Key Question:

"What is the depth of a tree?"

Let's think recursively:

The depth of a tree = 
  1 (current node) + max(depth of left subtree, depth of right subtree)

Visual:
       root         Depth = ?
       / \
    left  right    Depth of left = ?   Depth of right = ?

If we KNOW the depth of left and right subtrees:
  Depth of tree = 1 + max(left_depth, right_depth)

This is PERFECT for recursion!

Building Intuition:

Example:
       3           Depth = ?
      / \
     9   20       Depth of 9 = ?   Depth of 20 = ?
        /  \
       15   7

Step 1: What's the depth of node 9?
  Node 9 has no children (both null)
  Depth = 1

Step 2: What's the depth of node 20?
  Node 20 has left child (15) and right child (7)
  Depth of 15 = 1 (no children)
  Depth of 7 = 1 (no children)
  Depth of 20 = 1 + max(1, 1) = 2

Step 3: What's the depth of root (3)?
  Depth of left (9) = 1
  Depth of right (20) = 2
  Depth of root = 1 + max(1, 2) = 3 ✓

🧠 Recursive Thinking - The Foundation

Base Case:

What's the simplest tree?
  → An empty tree (null)

What's the depth of an empty tree?
  → 0 (no nodes!)

Base Case:
  if (root == null) return 0;

Recursive Case:

For any node:
  1. Find depth of left subtree
  2. Find depth of right subtree
  3. Take the maximum of the two
  4. Add 1 (for current node)

Formula:
  depth = 1 + max(leftDepth, rightDepth)

The Complete Recursive Definition:

maxDepth(node):
  if node is null:
    return 0
  else:
    leftDepth = maxDepth(node.left)
    rightDepth = maxDepth(node.right)
    return 1 + max(leftDepth, rightDepth)

🎯 Solution 1: Recursive DFS (Most Natural)

The Complete Solution:

class Solution {
    public int maxDepth(TreeNode root) {
        // Base Case: Empty tree has depth 0
        // WHY? No nodes means no depth
        if (root == null) {
            return 0;
        }

        // Recursive Case:
        // 1. Find depth of left subtree
        int leftDepth = maxDepth(root.left);

        // 2. Find depth of right subtree
        int rightDepth = maxDepth(root.right);

        // 3. Depth of current tree = 1 + max of subtrees
        // WHY? Current node adds 1 to the maximum path below it
        return 1 + Math.max(leftDepth, rightDepth);
    }
}

Shorter Version (One-Liner):

class Solution {
    public int maxDepth(TreeNode root) {
        // All three steps in one line!
        return root == null ? 0 : 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
    }
}

Understanding the Logic:

if (root == null) return 0;
// Base case: No tree, no depth
// This is where recursion "bottoms out"

int leftDepth = maxDepth(root.left);
// "Hey left child, what's YOUR maximum depth?"
// Trust that recursion will give correct answer

int rightDepth = maxDepth(root.right);
// "Hey right child, what's YOUR maximum depth?"
// Again, trust the recursion

return 1 + Math.max(leftDepth, rightDepth);
// My depth = 1 (for me) + maximum of my children's depths
// Take the LONGER path (max)

🔍 Detailed Dry Run with Recursion Visualization

Let's trace through Example 1 step by step.

Input Tree:
       3
      / \
     9   20
        /  \
       15   7

Complete Recursion Call Tree:

CALL STACK VISUALIZATION:

Level 0: maxDepth(3)
│
├─ Recurse LEFT ──────────────────────┐
│                                      │
│  Level 1: maxDepth(9)               │
│  │                                   │
│  ├─ Recurse LEFT ─────┐            │
│  │                     │             │
│  │  Level 2: maxDepth(null)        │
│  │  │                  │             │
│  │  └─ return 0 ✓     │             │
│  │                     │             │
│  ├─ Recurse RIGHT ────┐            │
│  │                     │             │
│  │  Level 2: maxDepth(null)        │
│  │  │                  │             │
│  │  └─ return 0 ✓     │             │
│  │                                   │
│  └─ Compute: 1 + max(0, 0) = 1     │
│     return 1 ✓                      │
│                                      │
├─ Recurse RIGHT ─────────────────────┐
│                                      │
│  Level 1: maxDepth(20)              │
│  │                                   │
│  ├─ Recurse LEFT ─────┐            │
│  │                     │             │
│  │  Level 2: maxDepth(15)          │
│  │  │                  │             │
│  │  ├─ LEFT: maxDepth(null) → 0   │
│  │  ├─ RIGHT: maxDepth(null) → 0  │
│  │  └─ return 1 + max(0,0) = 1 ✓  │
│  │                     │             │
│  ├─ Recurse RIGHT ────┐            │
│  │                     │             │
│  │  Level 2: maxDepth(7)           │
│  │  │                  │             │
│  │  ├─ LEFT: maxDepth(null) → 0   │
│  │  ├─ RIGHT: maxDepth(null) → 0  │
│  │  └─ return 1 + max(0,0) = 1 ✓  │
│  │                                   │
│  └─ Compute: 1 + max(1, 1) = 2     │
│     return 2 ✓                      │
│                                      │
└─ Compute: 1 + max(1, 2) = 3         │
   return 3 ✓                          │

FINAL RESULT: 3

Step-by-Step Execution:

Call Order (DFS - goes deep first):

Call 1: maxDepth(3)
  Needs: leftDepth and rightDepth
  Calls maxDepth(9)...

Call 2: maxDepth(9)
  Needs: leftDepth and rightDepth
  Calls maxDepth(null)...

Call 3: maxDepth(null)  [9's left child]
  ← Returns: 0

Call 4: maxDepth(null)  [9's right child]
  ← Returns: 0

Back to Call 2: maxDepth(9)
  leftDepth = 0, rightDepth = 0
  ← Returns: 1 + max(0, 0) = 1

Back to Call 1: maxDepth(3)
  leftDepth = 1
  Now calls maxDepth(20)...

Call 5: maxDepth(20)
  Needs: leftDepth and rightDepth
  Calls maxDepth(15)...

Call 6: maxDepth(15)
  Calls maxDepth(null) [left] → 0
  Calls maxDepth(null) [right] → 0
  ← Returns: 1 + max(0, 0) = 1

Back to Call 5: maxDepth(20)
  leftDepth = 1
  Now calls maxDepth(7)...

Call 7: maxDepth(7)
  Calls maxDepth(null) [left] → 0
  Calls maxDepth(null) [right] → 0
  ← Returns: 1 + max(0, 0) = 1

Back to Call 5: maxDepth(20)
  leftDepth = 1, rightDepth = 1
  ← Returns: 1 + max(1, 1) = 2

Back to Call 1: maxDepth(3)
  leftDepth = 1, rightDepth = 2
  ← Returns: 1 + max(1, 2) = 3

FINAL: 3 ✓

Visual Return Flow:

Tree with return values:

       3           ← Returns 3 = 1 + max(1, 2)
      / \
     9   20       ← 9 returns 1    20 returns 2
        /  \         1 + max(0,0)  1 + max(1,1)
       15   7    ← 15 returns 1   7 returns 1
                    1 + max(0,0)   1 + max(0,0)

Each node:
  - Asks children for their depths
  - Children return their depths
  - Node computes: 1 + max(left, right)
  - Returns to parent

What Each Node "Sees":

Node 15 says:
  "My left is null (depth 0)"
  "My right is null (depth 0)"
  "My depth = 1 + max(0, 0) = 1"
  → Returns 1 to parent (20)

Node 7 says:
  "My left is null (depth 0)"
  "My right is null (depth 0)"
  "My depth = 1 + max(0, 0) = 1"
  → Returns 1 to parent (20)

Node 9 says:
  "My left is null (depth 0)"
  "My right is null (depth 0)"
  "My depth = 1 + max(0, 0) = 1"
  → Returns 1 to parent (3)

Node 20 says:
  "My left child (15) has depth 1"
  "My right child (7) has depth 1"
  "My depth = 1 + max(1, 1) = 2"
  → Returns 2 to parent (3)

Node 3 says:
  "My left child (9) has depth 1"
  "My right child (20) has depth 2"
  "My depth = 1 + max(1, 2) = 3"
  → Returns 3 (FINAL ANSWER!)

🎯 Solution 2: Iterative DFS (Using Stack)

We can solve this iteratively using a stack!

The Idea:

Instead of recursion, use a stack
Track both the node AND its current depth

Process:
  1. Push root with depth 1
  2. While stack not empty:
     a. Pop node and its depth
     b. Update maximum depth seen so far
     c. Push children with depth+1
  3. Return maximum depth

Implementation:

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        // Stack stores pairs of (node, depth at that node)
        Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
        stack.push(new Pair<>(root, 1));

        int maxDepth = 0;

        while (!stack.isEmpty()) {
            Pair<TreeNode, Integer> pair = stack.pop();
            TreeNode node = pair.getKey();
            int depth = pair.getValue();

            // Update maximum depth
            maxDepth = Math.max(maxDepth, depth);

            // Push children with incremented depth
            if (node.left != null) {
                stack.push(new Pair<>(node.left, depth + 1));
            }
            if (node.right != null) {
                stack.push(new Pair<>(node.right, depth + 1));
            }
        }

        return maxDepth;
    }
}

Without Pair Class (Using Two Stacks):

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        Stack<TreeNode> nodeStack = new Stack<>();
        Stack<Integer> depthStack = new Stack<>();

        nodeStack.push(root);
        depthStack.push(1);

        int maxDepth = 0;

        while (!nodeStack.isEmpty()) {
            TreeNode node = nodeStack.pop();
            int depth = depthStack.pop();

            maxDepth = Math.max(maxDepth, depth);

            if (node.left != null) {
                nodeStack.push(node.left);
                depthStack.push(depth + 1);
            }
            if (node.right != null) {
                nodeStack.push(node.right);
                depthStack.push(depth + 1);
            }
        }

        return maxDepth;
    }
}

Dry Run - Iterative DFS:

Tree:
       3
      / \
     9   20
        /  \
       15   7

Stack Operations (node, depth):

Initial:
  stack = [(3, 1)]
  maxDepth = 0

Iteration 1:
  Pop: (3, 1)
  maxDepth = max(0, 1) = 1
  Push: (9, 2), (20, 2)
  stack = [(9, 2), (20, 2)]

Iteration 2:
  Pop: (20, 2)
  maxDepth = max(1, 2) = 2
  Push: (15, 3), (7, 3)
  stack = [(9, 2), (15, 3), (7, 3)]

Iteration 3:
  Pop: (7, 3)
  maxDepth = max(2, 3) = 3
  No children to push
  stack = [(9, 2), (15, 3)]

Iteration 4:
  Pop: (15, 3)
  maxDepth = max(3, 3) = 3
  No children to push
  stack = [(9, 2)]

Iteration 5:
  Pop: (9, 2)
  maxDepth = max(3, 2) = 3
  No children to push
  stack = []

Stack empty → return 3 ✓

🎯 Solution 3: BFS (Level Order Traversal)

We can also use BFS with a queue!

The Idea:

Process tree level by level
Count the number of levels

Each complete level adds 1 to depth

Implementation:

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        int depth = 0;

        while (!queue.isEmpty()) {
            // Process one complete level
            int levelSize = queue.size();

            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();

                // Add children for next level
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }

            // Completed one level
            depth++;
        }

        return depth;
    }
}

Dry Run - BFS:

Tree:
       3           Level 1
      / \
     9   20       Level 2
        /  \
       15   7     Level 3

Queue Operations:

Initial:
  queue = [3]
  depth = 0

Level 1:
  levelSize = 1 (queue has 1 node)
  Process 3: add children 9, 20
  queue = [9, 20]
  depth = 1

Level 2:
  levelSize = 2 (queue has 2 nodes)
  Process 9: no children
  Process 20: add children 15, 7
  queue = [15, 7]
  depth = 2

Level 3:
  levelSize = 2 (queue has 2 nodes)
  Process 15: no children
  Process 7: no children
  queue = []
  depth = 3

Queue empty → return 3 ✓

Why BFS Works:

Each iteration of while loop = one complete level

Level 1: [3]           → depth = 1
Level 2: [9, 20]       → depth = 2
Level 3: [15, 7]       → depth = 3

Number of levels = maximum depth!

📊 Comparison: DFS vs BFS

Recursive DFS:

✓ Cleanest code
✓ Most intuitive for trees
✓ Natural recursion
✗ Uses call stack (potential stack overflow)

Time: O(n)
Space: O(h) where h = height

Iterative DFS:

✓ Avoids recursion stack overflow
✓ Same logic as recursive
✗ Need to track depth manually
✗ Slightly more code

Time: O(n)
Space: O(h)

BFS:

✓ Level-by-level intuition
✓ Natural for "depth" concept
✗ More space for wide trees
✗ Slightly more complex

Time: O(n)
Space: O(w) where w = max width

Which to Use?

For this problem: All work equally well!

Choose based on preference:
  - Learning recursion? → Recursive DFS
  - Fear stack overflow? → Iterative DFS or BFS
  - Like level-order? → BFS

My recommendation: Recursive DFS (cleanest!)

📊 Complexity Analysis

Recursive DFS Solution:

Time Complexity: O(n)

Where n = number of nodes in the tree

Why?
  - We visit each node exactly once
  - At each node, we do O(1) work
  - Total: n × O(1) = O(n)

Example:
  Tree with 7 nodes → 7 function calls
  Tree with 100 nodes → 100 function calls

Space Complexity: O(h)

Where h = height of the tree

Why?
  - Recursion uses call stack
  - Maximum depth of call stack = height of tree

Best case (balanced tree): O(log n)
  Example: Perfect binary tree with 15 nodes
  Height = 4 → Stack depth = 4

Worst case (skewed tree): O(n)
  Example: Left-skewed tree
    1
   /
  2
 /
3
  Height = 3 → Stack depth = 3

For n nodes in skewed tree: h = n

Iterative Solutions:

Time Complexity: O(n) - Same as recursive

Space Complexity:

DFS (Stack): O(h)
  Stack holds nodes along one path
  Best: O(log n), Worst: O(n)

BFS (Queue): O(w) where w = maximum width
  Queue holds all nodes at one level

  Example: Perfect binary tree
       1
      / \
     2   3
    / \ / \
   4  5 6  7

  Level 3 has 4 nodes (width = 4)
  Queue could hold all 4

  Worst case: w = n/2 (last level of complete tree)
  Space: O(n)

⚠️ Common Mistakes

Mistake 1: Counting Edges Instead of Nodes

// ❌ WRONG - Counts edges, not nodes
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    if (root.left == null && root.right == null) return 0;  // Leaf = 0?
    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

// Tree:  1
//       /
//      2
// This returns 1, but should return 2 (two nodes!)

// ✓ CORRECT - Counts nodes
public int maxDepth(TreeNode root) {
    if (root == null) return 0;  // Only this base case needed!
    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

Mistake 2: Not Adding 1 for Current Node

// ❌ WRONG - Forgets current node
return Math.max(maxDepth(root.left), maxDepth(root.right));

// Tree:  1
//       / \
//      2   3
// This returns 1, but should return 2!
// (Forgets to count root!)

// ✓ CORRECT - Adds 1 for current node
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));

Mistake 3: Using Min Instead of Max

// ❌ WRONG - Uses min (gives minimum depth!)
return 1 + Math.min(maxDepth(root.left), maxDepth(root.right));

// Tree:    1
//         / \
//        2   3
//           / \
//          4   5
// This returns 2, but should return 3!
// (Takes shorter path instead of longer)

// ✓ CORRECT - Uses max
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));

Mistake 4: Forgetting Null Check

// ❌ WRONG - NullPointerException!
public int maxDepth(TreeNode root) {
    int leftDepth = maxDepth(root.left);   // Crash if root is null!
    int rightDepth = maxDepth(root.right);
    return 1 + Math.max(leftDepth, rightDepth);
}

// ✓ CORRECT - Check null first
public int maxDepth(TreeNode root) {
    if (root == null) return 0;  // Handle null first!
    int leftDepth = maxDepth(root.left);
    int rightDepth = maxDepth(root.right);
    return 1 + Math.max(leftDepth, rightDepth);
}

Mistake 5: BFS - Not Processing Complete Level

// ❌ WRONG - Increments depth for each node
while (!queue.isEmpty()) {
    TreeNode node = queue.poll();
    depth++;  // Wrong! Counts nodes, not levels
    // ...
}

// ✓ CORRECT - Processes complete level
while (!queue.isEmpty()) {
    int levelSize = queue.size();  // Get level size first!
    for (int i = 0; i < levelSize; i++) {
        TreeNode node = queue.poll();
        // ...
    }
    depth++;  // Increment once per level
}

🎯 Pattern Recognition - The Depth/Height Pattern

This problem introduces the Tree Depth pattern!

Core Pattern: Calculate Tree Property Recursively

Template for tree depth/height:

int property(TreeNode node) {
  // Base case: null node
  if (node == null) return baseValue;

  // Recursive case
  int left = property(node.left);
  int right = property(node.right);

  // Combine results
  return 1 + combine(left, right);
}

For max depth: combine = max
For min depth: combine = min (with extra logic)
For diameter: different calculation

1. Minimum Depth of Binary Tree (Problem 134)

Difference from max depth:
  - Need SHORTEST path to a LEAF
  - Can't just use min!

Why?
     1
    /
   2

  If we use min(left, right):
    left = 1, right = 0
    min(1, 0) = 0 ✗ WRONG!

  Must check: is this actually a leaf path?

2. Diameter of Binary Tree

Diameter = longest path between any two nodes

Formula:
  For each node:
    diameter = leftDepth + rightDepth
    (don't add 1!)

  Return maximum diameter seen

3. Balanced Binary Tree

Check if height difference between left and right ≤ 1
  At EVERY node!

Uses depth calculation as helper

4. Count Complete Tree Nodes

Uses depth to optimize counting
Perfect binary tree: nodes = 2^depth - 1

When to Use This Pattern:

✓ Finding tree depth/height
✓ Finding paths in trees
✓ Calculating tree properties (diameter, balance)
✓ Any "longest/shortest path" in tree

📝 Quick Revision Notes

🎯 Core Concept

Maximum depth = number of nodes from root to farthest leaf. Use recursion: depth = 1 + max(leftDepth, rightDepth). Base case: null → 0. Each node adds 1, takes maximum of children's depths. Can use DFS (recursive/iterative) or BFS (count levels).

⚡ Quick Implementation

// Recursive DFS (Recommended)
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

// BFS (Alternative)
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);
    int depth = 0;
    while (!q.isEmpty()) {
        int size = q.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = q.poll();
            if (node.left != null) q.offer(node.left);
            if (node.right != null) q.offer(node.right);
        }
        depth++;
    }
    return depth;
}

🔑 Key Insights

Recursion Formula:

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

Why?
  - 1: Current node counts
  - max: Take the LONGER path
  - Recursion handles all nodes automatically

Return Value Meaning:

return 0   → "I'm null, don't count me"
return 1   → "I'm a leaf, count just me"
return 2   → "I have children, longest path through me is 2"
return 3   → "Longest path through me is 3"

Why Max (not Min)?

Maximum depth = LONGEST path
We want the DEEPEST leaf
So we take MAX of children's depths

Min would give SHORTEST path (different problem!)

🎪 Memory Aid

"One for me, max of my kids"
"Null returns zero, I add one"
"Deeper child wins!"

⚠️ Don't Forget

  • Base case: null → 0 (not 1!)
  • Add 1 for current node (don't forget!)
  • Use max (not min) for maximum depth
  • Count nodes (not edges)
  • BFS: process complete level (not individual nodes)
  • Trust recursion (don't overthink it!)

🔗 Pattern Template

import java.util.LinkedList;
import java.util.Queue;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }

    public static TreeNode buildTree(Integer[] arr) {
        if (arr == null || arr.length == 0 || arr[0] == null) {
            return null;
        }

        TreeNode root = new TreeNode(arr[0]);
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        int i = 1;
        while (!queue.isEmpty() && i < arr.length) {
            TreeNode current = queue.poll();

            // Process left child
            if (i < arr.length) {
                if (arr[i] != null) {
                    current.left = new TreeNode(arr[i]);
                    queue.offer(current.left);
                }
                i++;
            }

            // Process right child
            if (i < arr.length) {
                if (arr[i] != null) {
                    current.right = new TreeNode(arr[i]);
                    queue.offer(current.right);
                }
                i++;
            }
        }

        return root;
    }    
}

class Solution {
  public int maxDepth(TreeNode root) {
    // Approach 1 - Recursive DFS.
    return recursiveDFS(root);

    // // If time permits, check both methods also.
    // iterativeDFS(root)
    // iterativeBFS(root)
  }

  private int recursiveDFS(TreeNode root) {
    // base case 1 - reached leaf nodes.
    if(root == null) {
      return 0;
    }

    // check child nodes now
    return 1 + Math.max(recursiveDFS(root.left), recursiveDFS(root.right));
  }

  public static void main(String[] args) {
    Solution s = new Solution();
    System.out.println(s.maxDepth(TreeNode.buildTree(new Integer[] {3,9,20,null,null,15,7})));
    System.out.println(s.maxDepth(TreeNode.buildTree(new Integer[] {1,null,2})));
  }
}


// This pattern works for:
// - Maximum depth (use max)
// - Minimum depth (use min with leaf check)
// - Path sum calculations
// - Tree balance checks

🎉 Congratulations!

You've mastered tree depth calculation with recursion!

What You Learned:

Depth calculation - Counting nodes from root to leaf
Recursive formula - 1 + max(left, right)
Base case - null → 0
Multiple approaches - Recursive DFS, Iterative DFS, BFS
Return value meaning - What each node returns to parent
Visual recursion - Complete call stack trace
Common mistakes - Edges vs nodes, min vs max

Pattern Evolution:

Problem 131 (Same Tree):
  Return: boolean (true/false)
  Combine: left && right

Problem 132 (Symmetric Tree):
  Return: boolean
  Combine: left && right (with cross pattern)

Problem 133 (Maximum Depth):
  Return: int (depth)
  Combine: 1 + max(left, right)

Same recursion structure, different return types!

Next Steps:

Try these to reinforce the pattern: - Problem 134: Minimum Depth (similar but tricky!) - Problem 112: Path Sum (uses depth concept) - Diameter of Binary Tree (uses depth as helper)

You're building strong tree recursion skills! 🌳🚀✨