Lowest Common Ancestor of a Binary Search Tree in Python

The Lowest Common Ancestor (LCA) of two nodes in a binary tree is the lowest node that has both nodes as descendants. In a binary search tree, we can use the BST property to find the LCA efficiently.

6 2 8 0 4 7 9 3 5 Root (LCA of 2 and 8)

Algorithm Steps

To find the LCA in a binary tree, we follow these steps ?

  • If the tree is empty, return None
  • If either p or q equals the root, return root
  • Recursively find LCA in left subtree
  • Recursively find LCA in right subtree
  • If both left and right return non-null values, current root is the LCA
  • Otherwise, return the non-null value (left or right)

Example

Let's implement the LCA algorithm for a binary tree ?

class TreeNode:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

class Solution:
    def lowestCommonAncestor(self, root, p, q):
        if not root:
            return None
        if p == root or q == root:
            return root
        
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        
        if left and right:
            return root
        return left or right

def insert(temp, data):
    if data is None:
        return
    queue = [temp]
    while queue:
        node = queue.pop(0)
        if not node.left:
            node.left = TreeNode(data)
            break
        else:
            queue.append(node.left)
        if not node.right:
            node.right = TreeNode(data)
            break
        else:
            queue.append(node.right)

def make_tree(elements):
    if not elements:
        return None
    root = TreeNode(elements[0])
    for element in elements[1:]:
        if element is not None:
            insert(root, element)
    return root

def search_node(root, element):
    if root is None:
        return None
    if root.data == element:
        return root
    
    left_result = search_node(root.left, element)
    if left_result:
        return left_result
    
    return search_node(root.right, element)

# Create the binary tree
tree_data = [6, 2, 8, 0, 4, 7, 9, None, None, 3, 5]
root = make_tree(tree_data)

# Find LCA of nodes with values 2 and 8
solution = Solution()
node_2 = search_node(root, 2)
node_8 = search_node(root, 8)
lca = solution.lowestCommonAncestor(root, node_2, node_8)

print(f"LCA of 2 and 8: {lca.data}")
LCA of 2 and 8: 6

BST Optimized Approach

For Binary Search Trees, we can use the BST property for a more efficient solution ?

class BSTSolution:
    def lowestCommonAncestor(self, root, p, q):
        if not root:
            return None
            
        # If both nodes are smaller than root, LCA is in left subtree
        if p.data < root.data and q.data < root.data:
            return self.lowestCommonAncestor(root.left, p, q)
        
        # If both nodes are greater than root, LCA is in right subtree
        if p.data > root.data and q.data > root.data:
            return self.lowestCommonAncestor(root.right, p, q)
        
        # If one node is on left and other on right, root is LCA
        return root

# Using BST optimized approach
bst_solution = BSTSolution()
lca_bst = bst_solution.lowestCommonAncestor(root, node_2, node_8)
print(f"LCA using BST approach: {lca_bst.data}")
LCA using BST approach: 6

Comparison

Approach Time Complexity Space Complexity Best For
General Binary Tree O(n) O(h) Any binary tree
BST Optimized O(h) O(h) Binary Search Trees

Conclusion

The LCA algorithm recursively searches both subtrees and returns the node where paths diverge. For BSTs, use the optimized approach that leverages the ordering property for better performance.

Updated on: 2026-03-25T07:17:59+05:30

717 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements