110. Balanced Binary Tree
Quick Identifier
- Topic: trees
- Pattern: Tree DFS (post-order)
- Difficulty: Easy
- Companies: Amazon, Google, Bloomberg, Meta, Apple
- Frequency: High
- LeetCode: 110
Quick Sights
- Time Complexity:
O(n)from the optimal approach. - Space Complexity:
O(h)from the optimal approach. - Core Mechanism: Given the
rootof a binary tree, determine if it is height-balanced: for every node, the absolute difference between the heights of its left and right subtrees is at most1.
Concept Explanation
Given the root of a binary tree, determine if it is height-balanced: for every node, the absolute difference between the heights of its left and right subtrees is at most 1.
State the invariant before coding: what partial result is already correct, what work remains, and what value or state each recursive/iterative step must preserve.
Recognition cues:
- "Balanced" binary tree definition (AVL-style height gap)
- Check every subtree, not only the root’s children
- Often solved by returning sentinel height
-1when imbalanced
Study Pattern (SDE3+)
- 0-3 min: restate I/O and brittle edges aloud, then verbalize two approaches with time/space before you touch the keyboard.
- Implementation pass: one-line invariant above the tight loop; state what progress you make each iteration.
- 5 min extension: pick one constraint twist (immutable input, stream, bounded memory, parallel readers) and explain what in your solution breaks without a refactor.
Diagram
This diagram shows the algorithm movement for this problem family.
Approaches
- Brute force —
O(n²)time — for each node, compute subtree heights with separate DFS each time. - Better —
O(n)time — cache heights in a map (two passes). - Optimal —
O(n)time /O(h)stack — single post-order DFS: return-1if child imbalanced or|left−right| > 1; else return1 + max(left, right).
Optimal Solution
Go
package main
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func isBalanced(root *TreeNode) bool {
var height func(*TreeNode) int
height = func(node *TreeNode) int {
if node == nil {
return 0
}
leftHeight := height(node.Left)
if leftHeight == -1 {
return -1
}
rightHeight := height(node.Right)
if rightHeight == -1 {
return -1
}
diff := leftHeight - rightHeight
if diff < 0 {
diff = -diff
}
if diff > 1 {
return -1
}
if leftHeight > rightHeight {
return 1 + leftHeight
}
return 1 + rightHeight
}
return height(root) != -1
}JavaScript
class TreeNode {
constructor(val = 0, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function isBalanced(root) {
function height(node) {
if (node === null) {
return 0;
}
const leftHeight = height(node.left);
if (leftHeight === -1) {
return -1;
}
const rightHeight = height(node.right);
if (rightHeight === -1) {
return -1;
}
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1;
}
return 1 + Math.max(leftHeight, rightHeight);
}
return height(root) !== -1;
}Walkthrough
Tree: 3 / 9,20 / null,null,15,7 — balanced.
| node | left | right | ok? | return height |
|---|---|---|---|---|
15 | 0 | 0 | yes | 1 |
7 | 0 | 0 | yes | 1 |
20 | 1 | 1 | yes | 2 |
9 | 0 | 0 | yes | 1 |
3 | 1 | 2 | yes | 3 |
If we hang a long chain under 9, height diff at 3 can exceed 1 → return -1 bubbles up.
Invariant: any subtree returns -1 iff it contains an imbalance anywhere inside.
Edge Cases
- Empty tree → balanced (
true) - Two nodes → balanced
- Left-skewed chain → not balanced except short chains
Pitfalls
- Checking only root’s left/right heights (misses imbalance deeper)
- Using unsigned math for diff (use
abson signed heights)
Similar Problems
- 104. Maximum Depth of Binary Tree — height without balance rule.
- 543. Diameter of Binary Tree — same post-order height plumbing.
- 236. Lowest Common Ancestor of a Binary Tree — different DFS goal, same recursion fluency.
Variants
- Return first violating node.
k-balanced (diff ≤k) generalization.
Mind-Map Tags
#trees #post-order #height #sentinel #bubble-up-failure
Mark this page when you finish learning it.
Last updated on
Spotted something unclear or wrong on this page?