Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Selected Reading
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.
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.
Advertisements
