-
-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathlowest_common_ancestor_binary_tree.py
141 lines (112 loc) · 5.32 KB
/
lowest_common_ancestor_binary_tree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Lowest Common Ancestor in Binary Tree
# Time Complexity : O(n) , Space Complexity : O(1)
"""
Binary trees are trees where any node can have only 0, 1 or 2 children, which are sorted in any order.
Lowest Common Ancestor (LCA) of two given nodes is the shared ancestor of n1 and n2 that is located farthest from the root
or the last common node that occurs on the paths from root node to those nodes.
Here, we first check if both numbers exist in tree or not, with exists_in_tree() function by recursively traversing the trees.
If yes then we find the LCA of both the elements with find_lca() function, which follows as :
if LCA isnt found yet, but current node is one of the elements, then current node is the LCA
else look for LCA in left and right subtree
if both elements are found in different subtrees, make current node as LCA
else if they are in same sub tree, return the LCA of that subtree
"""
class Node :
"""Class to define nodes of binary tree, with attributes data to store values, and left and right pointers"""
def __init__(self, value) :
self.data = value
self.left = None
self.right = None
def find_lca(node, n1, n2):
"""Finds LCA of 2 numbers by recursively searching in left and right subtree
input args : current node, the numbers whose lca is to be found, isFound list telling if the particular element is found
returns : lca if found else None
Time complexity : O(n), Space complexity : O(1)
"""
if node==None:
return None
# if one element is found in current node, we return it
# in normal case, both elements are found in different subtrees, called recursively, which is handeled later in this function
# there may also be the case when one element is ancestor of another, which is handeled here, as this node is tha lca
if node.data == n1:
return node
elif node.data == n2:
return node
# Recursive calls
lca_left = find_lca(node.left, n1, n2)
lca_right = find_lca(node.right, n1, n2)
if lca_left and lca_right: # if both are not none, that is 1 element is found in each subtree
return node # that means, current node is the lca
else: # both numbers in same sub tree
return lca_left if lca_left!=None else lca_right # return lca whichever is not none
def exists_in_tree(node, n):
"""This function finds if an element exists in a tree or not by recursively traversing the tree
input : current node and the element to be found
output : returns True if it exists, False if not
Time complexity : O(n), Space complexity : O(1)
"""
if node == None:
return False
if node.data == n:
return True
if exists_in_tree(node.left, n) or exists_in_tree(node.right, n):
return True
else:
return False
def lowest_common_ancestor_binary_tree(root, n1, n2):
"""This function checks if both elements are present in binary tree or not, and depending upon that returns proper value
input : root node of the tree, numbers whose lca is to be found
output : returns calculated LCA, if both exist, else None
Both Time and Space complexity are : O(1)
"""
if exists_in_tree(root,n1) and exists_in_tree(root,n2): # if both the elements exist in the tree
return find_lca(root, n1, n2) # then we calculate its LCA
else :
return None # otherwise we give answer None
def print_output(lca, n1, n2):
"""Prints LCA of two numbers with a proper message if it exists"""
if lca == None:
print("\nElement does not exist in tree.\n")
else:
print(f"\nlca({n1}, {n2}) = {lca.data}\n")
#============================= DRIVER CODE =============================
if __name__ == "__main__":
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
"""
1
/ \
2 3
/ \ /\
4 5 6 7
"""
lca = lowest_common_ancestor_binary_tree(root, 4, 5)
print_output(lca, 4, 5)
lca = lowest_common_ancestor_binary_tree(root, 2, 5)
print_output(lca, 2, 5)
lca = lowest_common_ancestor_binary_tree(root, 4, 2)
print_output(lca, 4, 2)
# OTHER EXAMPLES
"""lca = lowest_common_ancestor_binary_tree(root, 4, 7)
print_output(lca, 4, 7)
lca = lowest_common_ancestor_binary_tree(root, 2, 3)
print_output(lca, 2, 3)
lca = lowest_common_ancestor_binary_tree(root, 2, 1)
print_output(lca, 2, 1)"""
"""lca = lowest_common_ancestor_binary_tree(root, 1, 8)
print_output(lca, 1, 8)
lca = lowest_common_ancestor_binary_tree(root, 1, 1)
print_output(lca, 1, 1)
lca = lowest_common_ancestor_binary_tree(root, 2, 6)
print_output(lca, 2, 6)"""
"""lca = lowest_common_ancestor_binary_tree(root, 9, 8)
print_output(lca, 9, 8)
lca = lowest_common_ancestor_binary_tree(root, -1, 1)
print_output(lca, -1, 1)
lca = lowest_common_ancestor_binary_tree(root, -5, -6)
print_output(lca, -5, -6)"""