AlgoMaster Logo

Balanced Binary Tree

Last Updated: April 1, 2026

easy

Understanding the Problem

We need to check whether a binary tree is "height-balanced." That means for every single node in the tree, the heights of its left and right subtrees differ by at most 1. Not just the root. Every node.

This is a subtle but important detail. A tree could have left and right subtrees of the root with heights 3 and 3, which looks balanced at the top level. But if some node buried deep in the left subtree has children with heights 0 and 2, the tree is unbalanced. So we need a way to verify the balance condition at every node, not just the root.

The key observation is that this is naturally recursive. A tree is balanced if and only if: (1) the left subtree is balanced, (2) the right subtree is balanced, and (3) the height difference between the left and right subtrees at the current node is at most 1. All three conditions must hold.

Key Constraints:

  • Number of nodes in [0, 5000] → With n up to 5,000, even O(n^2) gives us 25 million operations, which is fine. But we can do better with O(n).
  • -10^4 <= Node.val <= 10^4 → Node values don't affect our algorithm at all. We only care about the tree's structure, not the values stored in it.
  • 0 nodes is valid → We need to handle the empty tree case. An empty tree is balanced.

Approach 1: Top-Down Recursion (Brute Force)

Intuition

The most natural approach follows directly from the definition. A tree is balanced if, at the current node, the left and right subtree heights differ by at most 1, AND both subtrees are themselves balanced.

So we write a height() helper that computes the height of any subtree, then at each node we call height() on the left child and right child, compare them, and recurse deeper. It's straightforward and easy to reason about.

The catch? We're computing heights from scratch at every node. The root calls height() on its children. Then when we recurse into the left child, that node calls height() on its children again, recomputing heights that were already computed. But for an Easy problem, this works just fine.

Algorithm

  1. If the current node is null, return true (an empty tree is balanced).
  2. Compute the height of the left subtree.
  3. Compute the height of the right subtree.
  4. If the absolute difference between the two heights is greater than 1, return false.
  5. Recursively check if the left subtree is balanced.
  6. Recursively check if the right subtree is balanced.
  7. Return true only if all three conditions are satisfied.

Example Walkthrough

1Start at root (3). Compute height of left subtree.
3check920157
1/6

Code

At each node, height() traverses the entire subtree, and then the recursive calls recompute heights on overlapping subtrees. What if we computed each node's height exactly once during a single bottom-up traversal?

Approach 2: Bottom-Up DFS (Optimal)

Intuition

Instead of computing heights separately and then checking balance, we combine both operations into a single recursive function. The idea is elegant: do a post-order DFS where each call returns the height of that subtree. But if at any point we detect an imbalance, we return a special sentinel value (-1) instead of a real height.

Think of it like this. In the top-down approach, we're asking each node "are you balanced?" and to answer, each node has to ask its entire subtree "how tall are you?" That's two separate questions requiring two separate traversals. In the bottom-up approach, we ask a single combined question: "how tall are you, or are you broken?" Each node gets the answer from its children, checks the balance condition, and passes the answer up. One traversal does everything.

Algorithm

  1. Define a helper function checkHeight(node) that returns the height of the subtree if balanced, or -1 if unbalanced.
  2. If the node is null, return 0 (base case: empty subtree has height 0).
  3. Recursively get the left subtree's height. If it's -1, immediately return -1 (left subtree is unbalanced, no need to check further).
  4. Recursively get the right subtree's height. If it's -1, immediately return -1.
  5. If the absolute difference between left and right heights exceeds 1, return -1 (current node violates balance).
  6. Otherwise, return 1 + max(leftHeight, rightHeight) as the valid height.
  7. In the main function, call checkHeight(root) and return true if the result is not -1.

Example Walkthrough

1Post-order DFS: visit leaves first, propagate heights up
3920157
1/6

Code