Binary Tree Height vs Depth: What Each Measures and Why It Matters

June 11, 20268 min read
dsaalgorithmsinterview-prepdata-structures
Binary Tree Height vs Depth: What Each Measures and Why It Matters
TL;DR
  • Depth counts edges from the root down to a node; the root always has depth 0
  • Height counts edges from a node down to its deepest leaf; leaves always have height 0
  • For any node on the longest root-to-leaf path: depth + height = tree height
  • Edge-counting vs node-counting conventions differ by exactly one; mixing them inside a single function is the classic AVL balance bug
  • LeetCode's "maximum depth" (problem 104) returns height in node-counting terms, not strict depth
  • BST operations and DFS stack space are both O(height), making height the complexity-critical measure
  • Self-balancing trees like AVL enforce O(log n) by bounding the difference between left and right subtree heights

Two words. Same tree. Opposite directions. And yet height and depth trip up more interview candidates than almost any other vocabulary confusion in binary trees. Engineers who've been writing recursive traversals for years swap them reflexively. Textbooks define them inconsistently. LeetCode named a problem "maximum depth of a binary tree" while the accepted solution computes height. It's a mess.

The actual answer is right here, before we go any further: depth counts edges from the root down to a node; height counts edges from a node down to its deepest leaf. Same tree, two directions. That's the whole distinction.

Depth Counts Down From the Root

The depth of a node tells you how far it sits from the root. Count edges along the path from root to your target. No tricks. Just counting.

Root depth = 0. Every level you descend adds one.

        1          ← depth 0
       / \
      2   3        ← depth 1
     / \
    4   5          ← depth 2

Node 1 has depth 0. Node 3 has depth 1. Node 4 has depth 2. Depth is a property of one specific node relative to the root. You can ask "what is the depth of node 4?" and get a single, unambiguous number.

Depth flows one direction: top to bottom.

Height Counts Up From the Leaves

Height measures the longest downward path from a node to any leaf in its subtree. Leaves have height 0. Every level up adds one.

Height of a node = the maximum number of edges on any path from that node down to a leaf.

        1          ← height 2
       / \
      2   3        ← height 1, height 0
     / \
    4   5          ← height 0, height 0

Node 1's height is 2 because the longest path hits node 4 or 5, two edges away. Node 2's height is 1. Node 3 is a leaf, so height 0.

The height of the tree is the height of the root.

The Same Tree, Measured Both Ways

Depth goes down, height goes up. Put them side by side on the same tree and the directions become obvious:

Tree showing depth values counting down from root (blue) and height values counting up from leaves (orange), with the callout that depth(D) + height(D) = tree height

Node F is the deepest node. Depth 3 (three edges from root). Height 0 (it's a leaf, nowhere left to go).

Node A is the root. Depth 0. Height 3.

For any node on the longest root-to-leaf path, depth plus height equals the tree's total height. Node D has depth 2 and height 1. Tree height is 3. That math will always work out, and it's the clearest way to check that you've computed both correctly.


The Off-by-One Problem Nobody Warned You About

Here's where things get genuinely annoying. Two valid conventions exist, and they both have defenders.

Edge-counting convention (CLRS and most textbooks):

  • Root depth = 0, leaf height = 0
  • Single-node tree height = 0
  • Empty tree height = -1

Node-counting convention (LeetCode and most real code):

  • Root depth = 1, leaf height = 1
  • Single-node tree height = 1
  • Empty tree height = 0

Two valid conventions, both in active use, differing by exactly one. If this feels like something that should have been standardized decades ago, you're right. It wasn't. Here we are.

# Edge-counting: leaf returns 0, empty subtree returns -1 def height_edges(node): if not node: return -1 return 1 + max(height_edges(node.left), height_edges(node.right)) # Node-counting: leaf returns 1, empty subtree returns 0 def height_nodes(node): if not node: return 0 return 1 + max(height_nodes(node.left), height_nodes(node.right))

Pick one. Say it out loud before you start coding. It costs two seconds and signals to an interviewer that you know the trap exists.

Mixing conventions inside a single function is how the classic AVL balance bug appears. The left subtree returns edge-counted height, the right returns node-counted height, the difference check produces nonsense, and the tree reports balanced when it absolutely is not. The code looks right. The tests might even pass. And then something downstream goes sideways in a way that's annoying to debug.


Why LeetCode 104 Is Called "Maximum Depth" When It Computes Height

LeetCode 104 asks for the "maximum depth" of a binary tree. The accepted solution returns the number of nodes along the longest root-to-leaf path. That is height in node-counting terms.

Not depth. Height.

LeetCode called it maxDepth. The implementation computes height. This is not a typo or a bug that someone will fix. It's the industry deciding that "maximum depth of the tree" and "height of the root" mean the same thing, and everyone just going with it.

When a problem says "maximum depth of the tree," it almost always means height. When it says "depth of node X," it means the distance from the root down to X.

# LeetCode 104 - named "maxDepth" but returns height in node-counting terms class Solution: def maxDepth(self, root: Optional[TreeNode]) -> int: if not root: return 0 return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

The base case returns 0 for empty and 1 for a leaf. Node-counting height. The function is named maxDepth. You now know more about this than LeetCode's problem name lets on.


Height Controls Every Operation's Cost

Height controls the worst-case cost of every tree operation. Search, insert, and delete in a binary search tree all run in O(height). On a balanced tree that's O(log n). On a degenerate tree where every node has exactly one child (a linked list wearing a tree hat), height is O(n) and every operation degrades accordingly.

Tree shapeHeightBST operation cost
Perfectly balancedfloor(log₂ n)O(log n)
Complete binary treefloor(log₂ n)O(log n)
Degenerate (one child per node)n - 1O(n)

This is why self-balancing binary search trees exist. An AVL tree maintains the invariant that the heights of any node's two subtrees differ by at most one. That bound propagates upward and keeps total height at O(log n) regardless of insertion order. The balance condition is defined entirely in terms of height, not depth.

Height Is Your Recursion's Space Budget

Recursive DFS uses call stack space proportional to height. Each call adds one frame, and the deepest path you traverse at any moment is the longest root-to-leaf path.

Space complexity of tree DFS = O(height).

For a balanced binary tree, that's O(log n). For a degenerate tree it's O(n), which for large inputs can overflow the hardware stack. This is why iterative traversal with an explicit stack exists: same algorithm, but the stack lives on the heap where you control its size.

Depth doesn't drive this cost. Recursion follows root-to-leaf paths, and the length of those paths is governed by height. For a closer look at how frames accumulate, recursion space complexity covers exactly this.


Where Height vs Depth Show Up in Interview Problems

Balanced tree checks. Any time you're verifying a tree is balanced (LeetCode 110), you're computing heights of subtrees and comparing them. The depth of individual nodes is irrelevant.

Diameter problems. LeetCode 543 (Diameter of Binary Tree) finds the longest path through any node. The solution computes height at each node and returns the sum of left and right subtree heights. Height propagates up through the recursion as the return value.

Complexity questions. When an interviewer asks why a BST operation runs in O(log n), the right answer involves height. "The tree has O(log n) height when balanced" is precise. "The tree has O(log n) depth" means something slightly different and will get noticed.

AVL and Red-Black tree explanations. Both self-balancing schemes define their invariants in terms of node heights. If you're explaining these in a system design round, you'll need the distinction to be precise about how the invariant enforces O(log n) operations.

Explaining these concepts out loud, under time pressure, is harder than it looks. SpaceComplexity runs voice-based mock interviews with rubric feedback on precision and communication, not just code correctness.


The Short Version

  • Depth: edges from the root down to a node. Root = 0.
  • Height of a node: edges from that node down to its deepest leaf. Leaf = 0.
  • Height of the tree: height of the root = depth of the deepest leaf.
  • Edge-counting vs node-counting: always off by one. State your convention before you code.
  • "Maximum depth of the tree" in LeetCode parlance means height.
  • Complexity: tree operations and DFS stack space are both O(height).

Further Reading