Problem#
Implement a function to check if a tree is balanced.
Definition#
Height-balanced binary tree: is defined as a binary tree in which the depth of the two sub-trees of every node never differ by more than 1.
Examples#
Example 1
1
2
3
4
5
3
/ \
9 20
/ \
15 7
1
2
Input: root = [ 3 , 9 , 20 , null , null , 15 , 7 ]
Output: true
Example 2:
1
2
3
4
5
6
7
1
/ \
2 2
/ \
3 3
/ \
4 4
1
2
Input: root = [ 1 , 2 , 2 , 3 , 3 , null , null , 4 , 4 ]
Output: false
Example 3:
1
2
Input: root = []
Output: true
Solution#
Method 1 - Difference of Height at Each Node Should Not Be Greater Than 1#
Code#
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public boolean isBalanced (Node root) {
if (root == null ) {
return true ; //tree is empty
}
int lh = height(root.left );
int rh = height(root.right );
if (isBalanced(root.left ) && isBalanced(root.right ) &&
Math.abs (lh - rh) < = 1) {
return true ;
} else {
return false ;
}
return true ;
}
Complexity#
Time complexity - O(n^2)
. For each node, we are calculating height again and again, which takes O(n) time. Hence O(n^2).
Space Complexity - O(1)
Refer the problem - Maximum Depth of Binary Tree to see how to get the height.
Method 2 - Optimise Height Calculation From Method 1#
When the tree is massively unbalanced - for eg. a million nodes deep on one side and three deep on the other, then method 1 will blow up. To fix this, we can optimize on how we calculate the height in previous solution.
We are seeing that we are again and again calculating the height of the tree. This can be done in 1 method itself, if we use pointers:
Code#
C
Java
Java
1
2
3
4
5
6
7
8
9
10
11
bool isBalanced (Node root, out int * height) {
if (root == null) {
height = 0
return true
}
int heightLeft = 0 , heightRight = 0 ;
//height is set by the isHeightBalanced function
boolean balance = isHeightBalanced (root.left, & heightLeft) && isHeightBalanced (root.right, & heightRight);
height = max (* heightLeft, * heightRight) + 1
return balance and abs (* heightLeft - * heightRight) <= 1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean isBalanced (TreeNode root) {
return heightBalancedPair(root).balanced ;
}
static class HeightBalancedPair {
int height;
boolean balanced;
}
private HeightBalancedPair heightBalancedPair (TreeNode root) {
if (root == null ) {
return new HeightBalancedPair(0, true );
}
HeightBalancedPair left = heightBalancedPair(root.left );
HeightBalancedPair right= heightBalancedPair(root.right );
int height = Math.max (left.height , right.height ) + 1;
boolean balanced = Math.abs (left.height - right.height ) < 2 && left.balanced && right.balanced ;
return new HeightBalancedPair(height, balanced);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public int checkHeight (TreeNode root) {
if (root == null )
return 0;
int leftHeight = checkHeight(root.left );
if (leftHeight == - 1)
return - 1; //not balanced
int rightHeight = checkHeight(root.right );
if (rightHeight == - 1)
return - 1;
int heightDiff = Math.abs (leftHeight - rightHeight);
if (heightDiff > 1)
return - 1;
else
return Math.max (leftHeight, rightHeight) + 1;
}
public boolean isBalanced (TreeNode root) {
if (checkHeight(root) == - 1)
return false ;
else
return true ;
}
Complexity#
Though this looks like a small optimization, but this will save lots of time.
Method 3 - Difference Between minDepth and maxDepth Should Be Less Than 1#
A tree is considered balanced when the difference between the min depth and max depth does not exceed 1.
Recursive algorithms always work well on trees, so here’s some code.
Code#
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool isBalanced (Node * root) {
return (maxDepth (root) - minDepth (root)) <= 1
}
int minDepth (Node * root) {
if (! root) {
return 0 ;
}
return 1 + min (minDepth (root -> left),
minDepth (root -> right));
}
int maxDepth (Node * root) {
if (! root) {
return 0 ;
}
return 1 + max (maxDepth (root -> left),
maxDepth (root -> right));
}
Complexity#
Time complexity- O(n)
For each node we calculate maxDepth - takes O(n) time, and minDepth takes O(n) time, and finally the boolean operation takes O(1) time.