LeetCode #110 Medium

Balanced Binary Tree

Balanced Binary Tree is LeetCode 110 (Easy). Given the root of a binary tree, return true if it is height-balanced.

  • A binary tree is height-balanced when, for every node, the heights of its left and right subtrees differ by at most 1.
  • The height of an empty subtree is 0; a single node has height 1.
  • An empty tree is balanced.
  • Up to 5,000 nodes, so recomputing heights from every node can reach about 12.5 million visits on a skewed tree; one pass is the goal.
Constraints
  • The number of nodes in the tree is in the range [0, 5000].
  • -10⁴ <= Node.val <= 10⁴
treedfsrecursion
Open on LeetCode ↗
02

Intuition

A balanced binary tree is one where no node is lopsided: at each node, the left and right subtree heights differ by at most 1.

The check at a node needs the heights of both children, and a height is only known once the whole subtree below has been seen. That points to post-order traversal: children first, then the node.

One recursive function can do both jobs by using a signal value: a special return value that means "stop". Heights are never negative, so -1 means "this subtree is unbalanced", and every ancestor passes it straight up.

How to spot this pattern

Any tree property that depends on both subtrees' results (height, diameter, sums, "is it valid below") is a post-order problem: compute children, combine at the node, return one value upward. When the answer is a yes/no and the parent needs a number, fold both into one return value with a sentinel such as -1.

03

Approach

Try it first

Before reading on: write height(node) recursively. Then think about calling it from every node to compare the two sides. How many times is a node near the bottom visited? Can one function return the height and the balance verdict together?

1

Define height(node) with a sentinel

It returns the subtree's height if that subtree is balanced, and -1 if it is not. An empty subtree returns 0. One function returning a height or -1 does both jobs in a single walk of the tree.

2

Recurse left, and stop early on -1

If the left subtree is already unbalanced, return -1 without visiting the right subtree. Once one subtree is unbalanced the whole tree is, so the rest of the work can be skipped.

3

Recurse right, then compare

This node is unbalanced, so return -1, when either:

  • the right subtree returned -1, or
  • the two heights differ by more than 1.

Each node is checked using its children's real heights, which post-order has just computed.

4

Report this node's height

Otherwise return 1 + max(left, right) so the parent can run the same comparison.

5

Answer at the root

The tree is balanced exactly when height(root) is not -1. -1 can only reach the root if some node failed the check.

04

Balanced Binary Tree solution in Python | C++ | Java

▶1class Solution:
▶2 def isBalanced(self, root: Optional[TreeNode]) -> bool:
▶3 def height(node):
▶4 if not node:
▶5 return 0
▶6 left = height(node.left)
▶7 if left == -1:
▶8 return -1
▶9 right = height(node.right)
▶10 if right == -1 or abs(left - right) > 1:
▶11 return -1
▶12 return 1 + max(left, right)
▶13 
▶14 return height(root) != -1
treehheight3920157post-order: leaves report first
nodes5each visited at most once
rule|L - R| ≤ 1at every node
Plan. A node can only be judged once both children have reported their heights, so the check runs post-order, from the leaves up. The same call returns -1 if anything below is unbalanced, so one pass answers both questions.
treehheight39120157left0right0gap0returns1leaf → height 1
left0empty
right0empty
height1reported to the parent
9 is a leaf: both children are empty (height 0), so it is balanced with height 1.
treehheight391201517left0right0gap0returns1leaf → height 1
left0empty
right0empty
height1reported to the parent
15 is a leaf: both children are empty (height 0), so it is balanced with height 1.
treehheight3912015171left0right0gap0returns1leaf → height 1
left0empty
right0empty
height1reported to the parent
7 is a leaf: both children are empty (height 0), so it is balanced with height 1.
treehheight39120215171left1right1gap0returns2|1 − 1| ≤ 1 → height 2
left1from node 15
right1from node 7
height2reported to the parent
Both children of 20 have reported. Their heights differ by 0, which is allowed, so this subtree is balanced. Pass its height 2 up to the parent.
treehheight339120215171left1right2gap1returns3|1 − 2| ≤ 1 → height 3
left1from node 9
right2from node 20
height3reported to the parent
Both children of 3 have reported. Their heights differ by 1, which is allowed, so this subtree is balanced. Pass its height 3 up to the parent.
treehheight339120215171height3balancedtrueroot height 3 → return true
height(root)3tree height
resulttrue
Balanced. Every node passed the check, and the root reports a height of 3. Each node was visited exactly once, so this is O(n).
05

Top-down height check

depth measures a subtree from scratch. isBalanced checks the root's two depths, then asks the same question of each child, exactly as the definition reads.

▶1class Solution:
▶2 def isBalanced(self, root: Optional[TreeNode]) -> bool:
▶3 def depth(node):
▶4 if not node:
▶5 return 0
▶6 return 1 + max(depth(node.left), depth(node.right))
▶7 
▶8 if not root:
▶9 return True
▶10 return (
▶11 abs(depth(root.left) - depth(root.right)) <= 1
▶12 and self.isBalanced(root.left)
▶13 and self.isBalanced(root.right)
▶14 )
06

Common pitfalls

Checking only the root

✗ Wrong
return abs(depth(root.left) - depth(root.right)) <= 1
✓ Right
return height(root) != -1  # checks every node

In the third example both of the root's subtrees have height 3, so this returns true, yet each node 2 has subtrees of heights 2 and 0. The rule applies at every node.

07

Edge cases

A long chain (every node has one child)

Balanced only up to 2 nodes. With 3 nodes in a line, the top node has heights 2 and 0 and returns -1. The recursion goes as deep as the chain, up to 5,000 frames, which fits in C++ and Java default stacks; Python needs sys.setrecursionlimit above its default of 1,000.

08

Complexity

Time
O(n)
Space
O(h)
Each node is visited once. The space is the recursion stack, as deep as the tree's height h: O(log n) for a balanced tree, O(n) for a chain.
09

Balanced binary tree vs related ideas

"Balanced" is used for several different things, which is a common source of confusion.

TermMeaningWhere it appears
Height-balanced binary treeat every node, subtree heights differ by ≤ 1LeetCode 110, AVL trees
Balanced binary search treea BST kept at O(log n) height by rotationsAVL, red-black trees, std::map, TreeMap
Complete binary treeevery level full except the last, filled from the leftbinary heaps
Perfect binary treeevery level completely fulla special case of all of the above
10

Balanced Binary Tree FAQ

How do you check if a binary tree is balanced?
  • Rule: at every node, left and right subtree heights differ by at most 1.
  • Method: one post-order DFS, height(node), that returns the height or -1 if the subtree is unbalanced.
  • At each node: get left height (stop if -1), get right height, return -1 if right is -1 or |left - right| > 1, else 1 + max(left, right).
  • Answer: height(root) != -1.
  • Complexity: O(n) time, O(h) space.
What is a height balanced binary tree?

A binary tree in which, for every node, the heights of the left and right subtrees differ by at most 1. This keeps the tree's height O(log n), which is why AVL trees enforce exactly this rule.

Is a balanced binary tree the same as a balanced binary search tree?

No. A balanced binary tree is only about shape. A balanced binary search tree must also keep the BST order (left < node < right) and usually restores balance with rotations after every insert or delete, as AVL and red-black trees do.