Bird
Raised Fist0
DSA Pythonprogramming

Check if Binary Tree is Balanced in DSA Python

Choose your learning style10 modes available
Mental Model
A balanced binary tree means no node has left and right subtrees differing in height by more than one.
Analogy: Imagine a tree where branches grow evenly on both sides so it doesn't lean or topple; if one side is much taller, the tree is unbalanced.
    1
   / \
  2   3
 /     \
4       5
Dry Run Walkthrough
Input: Tree: 1 with left child 2, right child 3; 2 has left child 4; 3 has right child 5
Goal: Determine if the tree is balanced by checking height differences at every node
Step 1: Check leaf node 4: height is 0, balanced
4 (leaf) height=0 balanced=true
Why: Leaf nodes have height 0 and are balanced by definition
Step 2: Check leaf node 5: height is 0, balanced
5 (leaf) height=0 balanced=true
Why: Leaf nodes have height 0 and are balanced by definition
Step 3: Check node 2: left height=0 (from 4), right height=-1 (no right child), difference=1, balanced
2 height=1 balanced=true
Why: Height difference 1 is allowed, so node 2 is balanced
Step 4: Check node 3: left height=-1 (no left child), right height=0 (from 5), difference=1, balanced
3 height=1 balanced=true
Why: Height difference 1 is allowed, so node 3 is balanced
Step 5: Check root node 1: left height=1 (from 2), right height=1 (from 3), difference=0, balanced
1 height=2 balanced=true
Why: Height difference 0 means root is balanced
Result:
1 (root) height=2 balanced=true
Tree is balanced
Annotated Code
DSA Python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def is_balanced(root):
    def check(node):
        if not node:
            return -1, True  # height, balanced
        left_height, left_balanced = check(node.left)  # check left subtree
        right_height, right_balanced = check(node.right)  # check right subtree
        height = 1 + max(left_height, right_height)  # current node height
        balanced = (left_balanced and right_balanced and abs(left_height - right_height) <= 1)  # balance check
        return height, balanced
    _, balanced = check(root)
    return balanced

# Driver code to test the example tree
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.right.right = TreeNode(5)
print("Tree is balanced" if is_balanced(root) else "Tree is not balanced")
if not node: return -1, True # height, balanced
Base case: empty subtree has height -1 and is balanced
left_height, left_balanced = check(node.left) # check left subtree
Recursively get left subtree height and balance
right_height, right_balanced = check(node.right) # check right subtree
Recursively get right subtree height and balance
height = 1 + max(left_height, right_height) # current node height
Calculate current node height from children
balanced = (left_balanced and right_balanced and abs(left_height - right_height) <= 1) # balance check
Check if current node is balanced based on children
return height, balanced
Return height and balance status up the call stack
OutputSuccess
Tree is balanced
Complexity Analysis
Time: O(n) because we visit each node once to compute height and balance
Space: O(h) where h is tree height due to recursion stack
vs Alternative: Naive approach recomputes height repeatedly causing O(n^2) time; this method computes height and balance in one pass
Edge Cases
Empty tree
Returns balanced true immediately
DSA Python
if not node:
    return -1, True  # height, balanced
Single node tree
Returns balanced true with height 0
DSA Python
height = 1 + max(left_height, right_height)  # current node height
Unbalanced tree with one side deeper by more than 1
Returns balanced false at the node where difference > 1
DSA Python
balanced = (left_balanced and right_balanced and abs(left_height - right_height) <= 1)  # balance check
When to Use This Pattern
When you need to check if a tree is balanced, use a bottom-up recursion that returns height and balance status together to avoid repeated height calculations.
Common Mistakes
Mistake: Calculating height separately for each node causing repeated work and O(n^2) time
Fix: Combine height and balance check in one recursive function returning both values
Mistake: Using height 0 for empty nodes causing off-by-one errors
Fix: Use height -1 for empty nodes so leaf nodes have height 0
Summary
Checks if a binary tree is balanced by verifying height differences at every node.
Use when you want to ensure the tree is balanced for efficient operations like search.
The key insight is to return height and balance status together in one recursion to avoid repeated height calculations.

Practice

(1/5)
1. What does it mean for a binary tree to be balanced?
easy
A. The tree has the same number of nodes on left and right
B. All nodes have two children
C. The height difference between left and right subtrees of every node is at most 1
D. The tree is a complete binary tree

Solution

  1. Step 1: Understand the balance condition

    A balanced binary tree means for every node, the height difference between its left and right subtree is at most 1.
  2. Step 2: Compare options with definition

    The height difference between left and right subtrees of every node is at most 1 matches this definition exactly, while others describe different tree properties.
  3. Final Answer:

    The height difference between left and right subtrees of every node is at most 1 -> Option C
  4. Quick Check:

    Balanced tree = height difference ≤ 1 [OK]
Hint: Balance means height difference ≤ 1 at every node [OK]
Common Mistakes:
  • Confusing balanced with complete tree
  • Thinking balanced means equal number of nodes
  • Assuming all nodes must have two children
2. Which of the following Python function signatures is correct to check if a binary tree is balanced?
easy
A. def is_balanced(root: List[int]) -> bool:
B. def is_balanced(root: int) -> int:
C. def is_balanced(tree: str) -> bool:
D. def is_balanced(root: Optional[TreeNode]) -> bool:

Solution

  1. Step 1: Identify correct parameter type for binary tree root

    The root of a binary tree is typically a TreeNode or None, so Optional[TreeNode] is correct.
  2. Step 2: Check return type for balance check

    The function should return a boolean indicating if the tree is balanced, so return type bool is correct.
  3. Final Answer:

    def is_balanced(root: Optional[TreeNode]) -> bool: -> Option D
  4. Quick Check:

    Function signature matches tree root and bool return [OK]
Hint: Use TreeNode or Optional[TreeNode] as input, bool as output [OK]
Common Mistakes:
  • Using int or str as input instead of TreeNode
  • Returning int instead of bool
  • Using list instead of tree node
3. What will be the output of the following code snippet?
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def check_height(node):
    if not node:
        return 0
    left_height = check_height(node.left)
    right_height = check_height(node.right)
    if left_height == -1 or right_height == -1 or abs(left_height - right_height) > 1:
        return -1
    return max(left_height, right_height) + 1

def is_balanced(root):
    return check_height(root) != -1

root = TreeNode(1, TreeNode(2, TreeNode(3)), TreeNode(4))
print(is_balanced(root))
medium
A. Runtime Error
B. True
C. None
D. False

Solution

  1. Step 1: Analyze tree structure

    The tree root has left child 2 with left child 3, and right child 4. Left subtree height is 2, right subtree height is 1.
  2. Step 2: Check balance condition

    At root, height difference is abs(2 - 1) = 1, which is allowed. But node 2 has left child 3 and no right child, so difference is abs(1 - 0) = 1, allowed. So tree is balanced.
  3. Step 3: Re-examine code logic

    Wait, the code returns -1 if difference > 1. Here difference never exceeds 1, so check_height returns height, is_balanced returns True.
  4. Step 4: Re-examine the tree carefully

    Node 2 has left child 3 (height 1) and no right child (height 0), difference is 1 (allowed). Root has left subtree height 2, right subtree height 1, difference 1 (allowed). So tree is balanced.
  5. Final Answer:

    True -> Option B
  6. Quick Check:

    Height difference ≤ 1 means balanced = True [OK]
Hint: Check height difference at each node; -1 means unbalanced [OK]
Common Mistakes:
  • Miscounting subtree heights
  • Confusing -1 return as False directly
  • Ignoring base case for None nodes
4. Find the bug in this code that checks if a binary tree is balanced:
def is_balanced(root):
    def height(node):
        if not node:
            return 0
        left = height(node.left)
        right = height(node.right)
        if abs(left - right) > 1:
            return False
        return max(left, right) + 1
    return height(root) != False
medium
A. Returning False instead of -1 breaks height calculation
B. Using != False instead of is not False causes error
C. Missing base case for leaf nodes
D. Not checking left and right subtree balance separately

Solution

  1. Step 1: Understand return values in height function

    The height function returns integer heights, but returns False when unbalanced, mixing types.
  2. Step 2: Identify impact on recursion

    Returning False breaks max(left, right) + 1 calculation because max expects integers, causing errors or wrong results.
  3. Final Answer:

    Returning False instead of -1 breaks height calculation -> Option A
  4. Quick Check:

    Use -1 for unbalanced, not False [OK]
Hint: Use -1 for unbalanced, not False, to keep height numeric [OK]
Common Mistakes:
  • Mixing boolean and integer return types
  • Incorrect final check with != False
  • Not propagating unbalanced signal properly
5. Given a binary tree, which approach efficiently checks if it is balanced without recalculating heights multiple times?
hard
A. Use a bottom-up recursion returning height or -1 if unbalanced
B. Calculate height for each node separately, then check balance
C. Traverse tree twice: once for height, once for balance
D. Use breadth-first search to check balance at each level

Solution

  1. Step 1: Understand naive approach drawbacks

    Calculating height separately for each node causes repeated work, leading to O(n²) time.
  2. Step 2: Identify efficient approach

    Bottom-up recursion returns height if balanced, or -1 if unbalanced, stopping early and avoiding repeated height calculations.
  3. Step 3: Compare other options

    Options B and C cause repeated calculations; D (BFS) does not directly check subtree heights efficiently.
  4. Final Answer:

    Use a bottom-up recursion returning height or -1 if unbalanced -> Option A
  5. Quick Check:

    Bottom-up recursion = efficient balance check [OK]
Hint: Return -1 early in recursion to avoid repeated height checks [OK]
Common Mistakes:
  • Using top-down approach causing repeated height calls
  • Trying BFS which doesn't check subtree heights easily
  • Checking balance after separate height computations
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard