-
Notifications
You must be signed in to change notification settings - Fork 3
/
112_Twitter_Find_Lowest_Common_Ancestor_of_Two_Nodes_In_A_Tree.py
executable file
·136 lines (103 loc) · 3.67 KB
/
112_Twitter_Find_Lowest_Common_Ancestor_of_Two_Nodes_In_A_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
"""
This problem was asked by Twitter.
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
Assume that each node in the tree also has a pointer to its parent.
According to the definition of LCA on Wikipedia(https://en.wikipedia.org/wiki/Lowest_common_ancestor):
“The lowest common ancestor is defined between two nodes v and w as the lowest node in T that
has both v and w as descendants (where we allow a node to be a descendant of itself).”
"""
class Node:
def __init__(self, data, left=None, right=None, parent=None):
self.data = data
self.left = left
self.right = right
self.parent = parent
def add_node(self, node):
if node.data <= self.data:
self.left = node
else:
self.right = node
node.parent = self
def __repr__(self):
return "{}".format(self.data)
def find_lowest_common_ancestor(node_a, node_b):
path_a = []
path_b = []
def helper(node, path= []):
if node.parent:
return helper(node.parent, [node.data]+path)
return [node.data]+path
# calculate paths for both
path_a = helper(node_a)
path_b = helper(node_b)
# common nodes
common_node = [n for n in path_a if n in path_b]
return common_node[-1] # the last common node is the LCA
# simpler method:
# observation the LCA is always between the two values
def find_lowest_common_ancestor_redux(root, node_a, node_b):
if root.data < node_a.data and root.data < node_b.data:
return find_lowest_common_ancestor_redux(root.right, node_a, node_b)
if root.data > node_a.data and root.data > node_b.data:
return find_lowest_common_ancestor_redux(root.left, node_a, node_b)
return root.data
# LCA can also be thought of as finding the merge point of two linked-lists(since parent is provided)
# idea from solution to my HackerRank "Find Merge Points of Two Lists"
def find_lowest_common_ancestor_redux_redux(node_a, node_b):
iter_1 = node_a
iter_2 = node_b
while iter_1 != iter_2:
if iter_1.parent is None:
iter_1 = node_b
else:
iter_1 = iter_1.parent
if iter_2.parent is None:
iter_2 = node_a
else:
iter_2 = iter_2.parent
return iter_2.data
if __name__ == '__main__':
"""
5
/ \
4 9
/ / \
3 6 13
\ / \
8 10 14
/
7
"""
a = Node(5)
b = Node(4)
c = Node(3)
d = Node(9)
e = Node(6)
f = Node(8)
g = Node(7)
h = Node(13)
i = Node(10)
j = Node(14)
a.add_node(b)
b.add_node(c)
a.add_node(d)
d.add_node(e)
e.add_node(f)
f.add_node(g)
d.add_node(h)
h.add_node(i)
h.add_node(j)
print(find_lowest_common_ancestor(b, d)) # 5
print(find_lowest_common_ancestor(a, b)) # 5
print(find_lowest_common_ancestor(c, b)) # 4
print(find_lowest_common_ancestor(g, e)) # 6
print("\n\n")
print(find_lowest_common_ancestor_redux(a,b, d)) # 5
print(find_lowest_common_ancestor_redux(a,a, b)) # 5
print(find_lowest_common_ancestor_redux(a,c, b)) # 4
print(find_lowest_common_ancestor_redux(a,g, e)) # 6
print("\n\n")
print(find_lowest_common_ancestor_redux_redux(b, d)) # 5
print(find_lowest_common_ancestor_redux_redux(a, b)) # 5
print(find_lowest_common_ancestor_redux_redux(c, b)) # 4
print(find_lowest_common_ancestor_redux_redux(g, e)) # 6