Instead of propagating from the root node to child nodes, we want to do post-order traversal; we traverse to left and right child nodes before we do the parent node.

AlgoMonster solution:

  • tree_height helper function returns -1 if the tree is unbalanced and the height of the tree if otherwise
# Returns -1 if is not a balanced binary tree. The height if it is.
def tree_height(tree):
	if tree is None:
        return 0
    left_height = tree_height(tree.left)
    right_height = tree_height(tree.right)
    if left_height is -1 or right_height is -1:
        return -1
    if abs(left_height - right_height) > 1:
        return -1
    return max(left_height, right_height) + 1
    
def is_balanced(tree: Node) -> bool:
    return tree_height(tree) != -1

NeetCode solution:

  • dfs returns a list where the first element is a boolean indicating whether the node’s subtrees are balanced; the 2nd element is the height of the sub-tree
def isBalanced(self, root: Optional[TreeNode]) -> bool:
	
	def dfs(node):
		if not node:
			return [True, 0]
		
		left, right = dfs(node.left), dfs(node.right)
		balanced = (abs(left[1] - right[1]) <= 1 
					and left[0] 
					and right[0])
		
		height = max(left[1], right[1]) + 1
		return [balanced, height]
	
	return dfs(root)[0]