Balanced Binary Tree - Complete Solution Guide
Balanced Binary Tree is LeetCode problem 110, a Easy level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
Given a binary tree, determine if it is height-balanced . Example 1: Input: root = [3,9,20,null,null,15,7] Output: true Example 2: Input: root = [1,2,2,3,3,null,null,4,4] Output: false Example 3: Input: root = [] Output: true Constraints: The number of nodes in the tree is in the range [0, 5000] . -10 4 <= Node.val <= 10 4
Detailed Explanation
We're tasked with determining if a given binary tree is "height-balanced." At its core, this property dictates that for *every single node* within the tree, the absolute difference between the height of its left subtree and the height of its right subtree must not exceed 1. It's a recursively defined property; if even one node fails this criterion, the entire tree is considered unbalanced. This isn't merely about the root node's children; the balance condition must hold true all the way down to the leaf nodes, checking every potential subtree. This pervasive requirement is what often makes the problem tricky if one only considers the root.
Solution Approach
The provided solution employs a clever depth-first search (DFS) approach that combines two critical tasks into a single recursive function: calculating the height of a subtree and simultaneously verifying its balance property. The `height` function traverses the tree in a post-order manner. For any given `node`, it first recursively determines the height and balance status of its left and right children. The elegance here is how an imbalance is signaled: if at any point a subtree (either left or right) is found to be unbalanced, its `height` call returns a special sentinel value, `-1`. This `-1` isn't a valid height, so when a parent node receives `-1` from either of its children, it immediately knows that an imbalance exists further down its branch. It then propagates this `-1` upwards, effectively short-circuiting further balance checks for that branch. If both children return valid heights, the current node then checks its own balance: `abs(left_height - right_height) > 1`. If it's imbalanced, it also returns `-1`. Otherwise, it calculates and returns its actual height `max(left_height, right_height) + 1`. The initial call `height(root)` then simply checks if the returned value is `-1`. If it is, the tree is unbalanced; otherwise, it's balanced. This strategy avoids redundant passes and ensures an efficient O(N) solution.
Step-by-Step Algorithm
- Step 1: Define a recursive helper function (e.g., `height` or `checkBalance`) that takes a tree node as input.
- Step 2: Base case: If the node is null, return 0 (height of an empty subtree is 0).
- Step 3: Recursively calculate the height of the left and right subtrees.
- Step 4: If either subtree is unbalanced (helper function returned -1) or the absolute difference between left and right subtree heights is greater than 1, return -1.
- Step 5: Otherwise, return the maximum of the left and right subtree heights plus 1 (the height of the current node).
- Step 6: In the main `isBalanced` function, call the helper function with the root node.
- Step 7: Return `true` if the helper function returned a non-negative value, `false` otherwise.
Key Insights
- **Bottom-Up Balance Validation with Height Propagation:** The problem's recursive nature—every node's subtrees must be balanced—is perfectly addressed by a bottom-up (post-order) DFS. Each node is responsible for not only computing its own subtree's height but also verifying its own balance condition *after* its children have reported their status. This ensures that an imbalance deep in the tree is detected and handled before higher-level nodes attempt their own checks.
- **Sentinel Value for Early Exit (Short-Circuiting):** The use of `-1` as a sentinel value is the critical optimization. Instead of a function that *only* returns height and then needing a separate boolean flag or a second pass to check balance, the `height` function itself communicates both states. If any recursive call encounters an imbalance or receives a `-1` from its children, it immediately propagates `-1` upwards. This effectively "short-circuits" the computation for that entire branch, preventing unnecessary calculations once an imbalance is confirmed.
- **Single-Pass O(N) Efficiency:** By cleverly combining height calculation and balance validation into one recursive traversal, the solution processes each node exactly once. Each node performs constant work (recursive calls, difference check, max operation). This results in an optimal O(N) time complexity, where N is the number of nodes, avoiding the potential O(N log N) or O(N^2) of naive approaches that might repeatedly calculate subtree heights.
Complexity Analysis
Time Complexity: O(n)
Space Complexity: O(h)
Topics
This problem involves: Tree, Depth-First Search, Binary Tree.
Companies
Asked at: Adobe, Apple, Capgemini, Meta, Uber, Yandex.