Check if Binary Tree is Balanced in DSA Typescript - Time & Space Complexity
We want to know how long it takes to check if a binary tree is balanced.
Specifically, how the time grows as the tree gets bigger.
Analyze the time complexity of the following code snippet.
function isBalanced(root: TreeNode | null): boolean {
function height(node: TreeNode | null): number {
if (!node) 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 Math.max(leftHeight, rightHeight) + 1;
}
return height(root) !== -1;
}
This code checks if a binary tree is balanced by measuring heights and stopping early if imbalance is found.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls to visit each node once.
- How many times: Each node is visited once to calculate height and check balance.
As the tree grows, the function visits each node once.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 visits |
| 100 | About 100 visits |
| 1000 | About 1000 visits |
Pattern observation: The work grows directly with the number of nodes.
Time Complexity: O(n)
This means the time to check balance grows linearly with the number of nodes in the tree.
[X] Wrong: "The function checks balance in O(n log n) time because it calculates height separately for each node."
[OK] Correct: This code calculates height once per node using a single recursion, avoiding repeated height calculations, so it runs in O(n) time.
Understanding this time complexity helps you explain efficient tree checks clearly and confidently in interviews.
"What if the code calculated height separately for left and right subtrees without early stopping? How would the time complexity change?"
Practice
Solution
Step 1: Understand balance condition
A balanced binary tree means no node has left and right subtree heights differing by more than 1.Step 2: Compare options
The height difference between left and right subtrees of every node is at most 1 correctly states this condition. Other options describe different tree properties.Final Answer:
The height difference between left and right subtrees of every node is at most 1 -> Option AQuick Check:
Balance = height difference ⤠1 [OK]
- Confusing balanced with complete tree
- Thinking balance means equal number of nodes
- Assuming all nodes must have two children
Solution
Step 1: Identify correct parameter and return types
The function should accept a TreeNode or null and return a boolean indicating balance.Step 2: Match options
function isBalanced(root: TreeNode | null): boolean matches this signature. Others have wrong parameter types or return types.Final Answer:
function isBalanced(root: TreeNode | null): boolean -> Option BQuick Check:
Input: TreeNode|null, Output: boolean [OK]
- Using number as input instead of TreeNode
- Returning number instead of boolean
- Using void return type
class TreeNode {
val: number;
left: TreeNode | null;
right: TreeNode | null;
constructor(val: number) {
this.val = val;
this.left = null;
this.right = null;
}
}
function checkHeight(node: TreeNode | null): number {
if (!node) return 0;
const leftHeight = checkHeight(node.left);
if (leftHeight === -1) return -1;
const rightHeight = checkHeight(node.right);
if (rightHeight === -1) return -1;
if (Math.abs(leftHeight - rightHeight) > 1) return -1;
return Math.max(leftHeight, rightHeight) + 1;
}
function isBalanced(root: TreeNode | null): boolean {
return checkHeight(root) !== -1;
}
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.left.left = new TreeNode(5);
console.log(isBalanced(root));Solution
Step 1: Analyze tree structure
The tree is left-heavy: root.left.left.left exists but right subtree is shallow, causing imbalance.Step 2: Trace checkHeight calls
checkHeight returns -1 when height difference > 1, so isBalanced returns false.Final Answer:
false -> Option DQuick Check:
Left-heavy deep subtree -> not balanced -> false [OK]
- Assuming tree is balanced without checking height difference
- Confusing return values of checkHeight
- Ignoring the -1 sentinel for imbalance
function isBalanced(root: TreeNode | null): boolean {
if (!root) return true;
const leftHeight = getHeight(root.left);
const rightHeight = getHeight(root.right);
if (Math.abs(leftHeight - rightHeight) > 1) return false;
return isBalanced(root.left) && isBalanced(root.right);
}
function getHeight(node: TreeNode | null): number {
if (!node) return 0;
return Math.max(getHeight(node.left), getHeight(node.right));
}Solution
Step 1: Review getHeight function
getHeight returns max height of children but misses adding 1 for current node.Step 2: Understand impact on balance check
Without adding 1, height is underestimated, causing wrong balance results.Final Answer:
getHeight does not add 1 to height, causing incorrect height calculation -> Option CQuick Check:
Height must include current node (+1) [OK]
- Forgetting to add 1 in height function
- Misusing Math.abs
- Missing base case for null root
Solution
Step 1: Understand inefficiency of top-down approach
Calculating height separately for each node causes repeated work and O(n²) time.Step 2: Use bottom-up approach
Return height if balanced, else -1 for imbalance, stopping early and using one traversal.Final Answer:
Use a bottom-up approach returning height or -1 for imbalance in one traversal -> Option AQuick Check:
Bottom-up single pass = efficient balance check [OK]
- Recalculating heights multiple times causing slow code
- Using breadth-first traversal which doesn't help balance check
- Storing heights globally without efficient update
Ready to prove it?
Pass the test and this pattern moves unknown
