Balanced Binary Tree
Easy TreeCheck if a binary tree is height-balanced using recursive depth calculation with early termination.
Problem Statement
Given a binary tree, determine if it is height-balanced.
A height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differs by more than one.
Example 1:
Input: root = [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
Output: true
Example 2:
Input: root = [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
Output: false
Constraints:
- The number of nodes in the tree is in the range
[0, 5000] -104 <= Node.val <= 104
Visual Idea Map
Think of checking balance like checking if a tower is stable. If one side is much taller than the other, the tower will topple. A balanced tree is "stable" at every level.
Step 1: Define Balance
A node is balanced if the height difference between its left and right subtrees is at most 1. The entire tree is balanced only if every node is balanced.
Step 2: Calculate Height Recursively
For each node, calculate the height of its left and right subtrees. Height = 1 + max(leftHeight, rightHeight). A null node has height 0.
Step 3: Check Balance at Each Node
At each node, check if |leftHeight - rightHeight| <= 1. If any node fails this check, the tree is not balanced.
Step 4: Early Termination (Optimization)
Instead of calculating height separately from checking balance, combine them. Return -1 (or a sentinel) when a subtree is unbalanced to propagate the failure up immediately.
Key Insight
The naive approach calculates height for each node separately (O(n²) worst case). The optimized approach combines height calculation with balance checking, achieving O(n) time by checking balance while calculating height.
Python Solution
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def checkHeight(node):
# Base case: empty subtree has height 0
if not node:
return 0
# Check left subtree, return -1 if unbalanced
leftHeight = checkHeight(node.left)
if leftHeight == -1:
return -1
# Check right subtree, return -1 if unbalanced
rightHeight = checkHeight(node.right)
if rightHeight == -1:
return -1
# Check balance at current node
if abs(leftHeight - rightHeight) > 1:
return -1
# Return actual height
return 1 + max(leftHeight, rightHeight)
return checkHeight(root) != -1
- Lines 1-5: Definition of TreeNode class with val, left, and right attributes.
- Line 8: Main function that initiates the balance check. Returns True if checkHeight doesn't return -1.
- Lines 9-10: Define nested helper function. An empty node (base case) has height 0.
- Lines 13-16: Recursively check left subtree. If it returns -1 (unbalanced), propagate -1 upward immediately.
- Lines 18-21: Recursively check right subtree. Same early termination logic.
- Lines 23-25: At current node, check if left and right heights differ by more than 1. If so, return -1.
- Lines 27-28: Return actual height: 1 (current node) + max of children's heights.
Java Solution
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
public boolean isBalanced(TreeNode root) {
return checkHeight(root) != -1;
}
private int checkHeight(TreeNode node) {
// Base case: empty subtree has height 0
if (node == null) {
return 0;
}
// Check left subtree
int leftHeight = checkHeight(node.left);
if (leftHeight == -1) {
return -1;
}
// Check right subtree
int rightHeight = checkHeight(node.right);
if (rightHeight == -1) {
return -1;
}
// Check balance at current node
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1;
}
// Return actual height
return 1 + Math.max(leftHeight, rightHeight);
}
}
- Lines 1-11: TreeNode class definition with constructors.
- Lines 14-16: Main method delegates to checkHeight, returns true if result isn't -1.
- Lines 18-21: Base case: null node returns height 0.
- Lines 24-27: Recursively get left subtree height, propagate -1 if unbalanced.
- Lines 30-33: Recursively get right subtree height, propagate -1 if unbalanced.
- Lines 36-38: Check balance condition using Math.abs() for absolute difference.
- Line 41: Return height: 1 + max of children heights.
C++ Solution
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
class Solution {
public:
bool isBalanced(TreeNode* root) {
return checkHeight(root) != -1;
}
private:
int checkHeight(TreeNode* node) {
// Base case: empty subtree has height 0
if (node == nullptr) {
return 0;
}
// Check left subtree
int leftHeight = checkHeight(node->left);
if (leftHeight == -1) {
return -1;
}
// Check right subtree
int rightHeight = checkHeight(node->right);
if (rightHeight == -1) {
return -1;
}
// Check balance at current node
if (abs(leftHeight - rightHeight) > 1) {
return -1;
}
// Return actual height
return 1 + max(leftHeight, rightHeight);
}
};
- Lines 1-8: TreeNode struct with constructors using initializer lists.
- Lines 12-14: Main function calls checkHeight and compares result to -1.
- Lines 17-20: Base case: nullptr returns 0 (empty subtree height).
- Lines 23-26: Recursively check left subtree via node->left pointer.
- Lines 29-32: Recursively check right subtree via node->right pointer.
- Lines 35-37: Use abs() from <cstdlib> to check height difference.
- Line 40: Return height using std::max from <algorithm>.
Complexity Analysis
Time Complexity: O(n)
Each node is visited exactly once. The algorithm computes height and checks balance in a single bottom-up pass. Unlike the naive O(n²) approach that calculates height separately for each node, we combine both operations.
Space Complexity: O(h)
The recursion stack uses O(h) space where h is the height of the tree. In the worst case (skewed tree), this becomes O(n). For a balanced tree, it's O(log n).
Why O(n) not O(n²)?
A naive approach would calculate height at each node separately: for each of n nodes, traverse up to O(n) nodes to find height. Our optimized approach uses bottom-up traversal with early termination — we compute height once per node and immediately return -1 if imbalance is detected, avoiding redundant work.
Edge Cases
Empty Tree (root = null)
An empty tree is considered balanced. Returns true.
Single Node Tree
A tree with only root has no children, so height difference is 0. Returns true.
Completely Skewed Tree (Linked List)
A tree where each node has only one child. Maximum imbalance at root. Returns false.
Deeply Nested Imbalance
Imbalance might occur deep in the tree. Early termination ensures we detect this without visiting remaining nodes.
Common Mistakes to Avoid
Mistake 1: Calculating height separately for each node
This leads to O(n²) time complexity. Always combine height calculation with balance checking in a single traversal.
Mistake 2: Forgetting to propagate -1 upward
If a subtree returns -1 (unbalanced), you must immediately return -1 without continuing to check other nodes.
Tip: Use a sentinel value
Using -1 as "unbalanced" is elegant because valid heights are always non-negative. This makes checking trivial: result == -1
Best Practice: Bottom-up approach
Post-order traversal (process children first, then current) is natural for this problem. You get children's heights before checking current node's balance.
Learn More
Want to dive deeper into the concepts behind tree properties and balance checking? Check out our comprehensive guide on SoftwareInLevels:
Understanding Tree Properties — From Basics to AdvancedThis three-level series covers tree properties from beginner analogies to hardware-level optimization, including balance conditions, AVL trees, and more.
Related Problems
Maximum Depth of Binary Tree
EasyCalculate tree height recursively — foundation for balance checking.
Minimum Depth of Binary Tree
EasyFind shortest path to leaf — complements maximum depth.
Binary Tree Inorder Traversal
EasyMaster tree traversal basics before tackling balance problems.
Symmetric Tree
EasyAnother tree property check using recursive comparison.