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
Program to find out the lowest common ancestor of a binary tree using Python
The Lowest Common Ancestor (LCA) of two nodes in a binary tree is the deepest node that has both nodes as descendants. A node can be considered a descendant of itself. This problem is commonly solved using recursive traversal.
So, if the input is like:
For x = 2 and y = 4, the output will be 3 because node 3 is the lowest common ancestor of both nodes 2 and 4.
Algorithm
The solution uses a depth-first search (DFS) approach:
- If the current node is null, return null
- If the current node matches either target node, return the node
- Recursively search left and right subtrees
- If both subtrees return non-null values, current node is the LCA
- Otherwise, return whichever subtree found a target node
Implementation
class TreeNode:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def insert(temp, data):
queue = []
queue.append(temp)
while queue:
temp = queue.pop(0)
if not temp.left:
if data is not None:
temp.left = TreeNode(data)
else:
temp.left = TreeNode(0)
break
else:
queue.append(temp.left)
if not temp.right:
if data is not None:
temp.right = TreeNode(data)
else:
temp.right = TreeNode(0)
break
else:
queue.append(temp.right)
def make_tree(elements):
if not elements:
return None
tree = TreeNode(elements[0])
for element in elements[1:]:
insert(tree, element)
return tree
def search_node(root, element):
if root is None:
return None
if root.data == element:
return root
res1 = search_node(root.left, element)
if res1:
return res1
res2 = search_node(root.right, element)
return res2
def find_lca(root, x, y):
def dfs(node):
if not node:
return None
# If current node is one of the target nodes
if node == x or node == y:
return node
# Search in left and right subtrees
left = dfs(node.left)
right = dfs(node.right)
# If both subtrees contain target nodes, current node is LCA
if left and right:
return node
# Return whichever subtree contains a target node
return left or right
return dfs(root)
# Example usage
root = make_tree([5, 3, 7, 2, 4, 1, 6])
node_x = search_node(root, 2)
node_y = search_node(root, 4)
lca = find_lca(root, node_x, node_y)
print(f"LCA of {node_x.data} and {node_y.data} is: {lca.data}")
The output of the above code is:
LCA of 2 and 4 is: 3
How It Works
The algorithm works by performing a post-order traversal of the binary tree. When it finds one of the target nodes, it returns that node up the recursion stack. If a node receives non-null values from both its left and right subtrees, it means both target nodes exist in different subtrees, making the current node their LCA.
Time Complexity
The time complexity is O(n) where n is the number of nodes in the tree, as we might visit all nodes in the worst case. The space complexity is O(h) where h is the height of the tree due to the recursion stack.
Conclusion
The LCA problem is efficiently solved using recursive DFS traversal. The key insight is that the LCA is the first node that has both target nodes in different subtrees during the bottom-up traversal.
