Balanced Binary Tree
Given the root of a binary tree, return true if the tree is height-balanced. Height-balanced means that at every node in the tree, the heights of its left and right subtrees differ by at most 1 — not just at the root. An empty tree is balanced, so a null root returns true. You return a boolean only, not the height.
- The number of nodes in the tree is in the range [0, 5000]
- -10⁴ <= Node.val <= 10⁴
- The balance condition must hold at every node, not only at the root
- An empty subtree has height 0
root = [3,9,20,null,null,15,7]trueroot = [1,2,2,3,3,null,null,4,4]falseroot = [1,2,3,4,5,6,null,8]trueroot = []trueA tree is balanced when, at every node, its two sides differ in height by at most 1 — not just at the root. So a tree can look perfectly even up top and still be disqualified by one lopsided node buried deep inside.
1 check |left height - right height| at EVERY node
/ \
2 2 at root: left height 3, right height 1
/ \ differ by 2 -> NOT balanced
3 3
/ \
4 4Read the picture: the left side plunges three levels down (2 → 3 → 4) while the right side stops at a single node. At the root that is a height gap of 2, which breaks the rule — so the whole tree is false. Notice this is a purely local test repeated everywhere; one bad node sinks the answer.
Here's the whole plan in one line. At each node, measure how tall its left side is and how tall its right side is; if those two heights differ by more than 1, the tree is not balanced. Do that test at every node, and the tree is balanced only if nobody fails.
To run that test a node needs the height of its left subtree and the height of its right subtree. It can't know those alone, so it asks both children first and waits for their heights to come back — the work happens after the children answer, which is post-order.
Once the two heights come back, a node has two separate things on its hands:
1 + max(left, right), because the parent needs it to run its own check.A function returns only one value, and the parent needs the height. So each node returns its height and, if its own two sides disagree by too much, flips a shared balanced flag kept outside the recursion. Every node gets its turn as the meeting point; balanced holds the final verdict at the end.
balanced = True
def height(node):
nonlocal balanced
if node is None:
return 0
left = height(node.left)
right = height(node.right)
if abs(left - right) > 1:
balanced = False # this node's two sides disagree too much
return 1 + max(left, right) # height I report upward
height(root)
return balancedOne thing to hold onto: the value a node returns is its height, but the thing we're really chasing is the boolean. When those two differ, return what the parent needs and keep the real answer in a variable on the side — exactly the move from Diameter of Binary Tree, where the side value was a running maximum instead of a flag.
Same tree. The number in [brackets] is the height each node returns upward; watch balanced flip at the root:
1 [4] sides (3, 1) differ by 2 -> balanced = False
/ \
2 [3] 2 [1] left 2: sides (2, 1) differ by 1 -> ok
/ \
3 [2] 3 [1] left 3: sides (1, 1) differ by 0 -> ok
/ \
4[1] 4[1] leaves: sides (0, 0) -> height 1balanced to False, and still reports its height 4 honestly.Follow the left 2 carefully: it passed its own test and reported honestly. Balance isn't broken by a node being deep — only by a node whose two sides disagree by too much. The root was the first place that comparison went wrong.
The value a node hands its parent isn't always the answer you're really chasing. When the two differ, return the one the parent needs (the height) and keep the real answer (the verdict) in a variable on the side. Each node is asked once and answers once, so nothing is recomputed — O(N) time, O(H) stack.
(An equivalent trick avoids the side variable: since real heights are never negative, let a node return -1 to mean "something below me is broken." A node returns its true height if all is well, or -1 the moment it or anything beneath it fails. That works only because -1 is impossible as a genuine height — pick a sentinel a real computation could produce and the code silently misreads good data as failure.)
Balance Calculus
"A single -1 return bubbles up the failure immediately (Early Exit)."
Strategy
We calculate height and check balance in one pass. If a subtree is unbalanced, we return -1 instead of height.
"Height = max(L, R) + 1"