1
- # https://en.wikipedia.org/wiki/Lowest_common_ancestor
2
- # https://en.wikipedia.org/wiki/Breadth-first_search
3
-
4
1
from __future__ import annotations
5
2
from queue import Queue
6
3
@@ -25,29 +22,27 @@ def swap(a: int, b: int) -> tuple[int, int]:
25
22
def create_sparse (max_node : int , parent : list [list [int ]]) -> list [list [int ]]:
26
23
"""
27
24
Create a sparse table that saves each node's 2^i-th parent.
28
-
29
- The given `parent` table should have the direct parent of each node in row 0.
30
- The function then fills in parent[j][i] = parent[j-1][parent[j-1][i]] for each j where 2^j < max_node.
31
-
25
+
26
+ The given ``parent`` table should have the direct parent of each node in row 0.
27
+ This function fills in:
28
+
29
+ parent[j][i] = parent[j - 1][parent[j - 1][i]]
30
+
31
+ for each j where 2^j is less than max_node.
32
+
32
33
For example, consider a small tree where:
33
34
- Node 1 is the root (its parent is 0),
34
35
- Nodes 2 and 3 have parent 1.
35
36
36
37
We set up the parent table for only two levels (row 0 and row 1)
37
38
for max_node = 3. (Note that in practice the table has many rows.)
38
-
39
- >>> # Create an initial parent table with 2 rows and indices 0..3.
40
- >>> parent0 = [0, 0, 1, 1] # 0 is unused; node1's parent=0, node2 and 3's parent=1.
39
+
40
+ >>> parent0 = [0, 0, 1, 1] # 0 is unused; node1's parent=0, nodes 2 and 3's parent=1.
41
41
>>> parent1 = [0, 0, 0, 0]
42
42
>>> parent = [parent0, parent1]
43
- >>> # We need at least (1 << j) < max_node holds only for j = 1 here since (1 << 1)=2 < 3 and (1 << 2)=4 !< 3.
44
43
>>> sparse = create_sparse(3, parent)
45
- >>> sparse[1][1], sparse[1][2], sparse[1][3]
44
+ >>> ( sparse[1][1], sparse[1][2], sparse[1][3])
46
45
(0, 0, 0)
47
- >>> # Explanation:
48
- >>> # For node 1: parent[1][1] = parent[0][parent[0][1]] = parent[0][0] = 0.
49
- >>> # For node 2: parent[1][2] = parent[0][parent[0][2]] = parent[0][1] = 0.
50
- >>> # For node 3: parent[1][3] = parent[0][parent[0][3]] = parent[0][1] = 0.
51
46
"""
52
47
j = 1
53
48
while (1 << j ) < max_node :
@@ -62,20 +57,20 @@ def lowest_common_ancestor(
62
57
) -> int :
63
58
"""
64
59
Return the lowest common ancestor (LCA) of nodes u and v in a tree.
65
-
66
- The lists `level` and `parent` must be precomputed. `level[i]` is the depth of node i,
67
- and `parent` is a sparse table where parent[0][i] is the direct parent of node i.
60
+
61
+ The lists ``level`` and ``parent`` must be precomputed. ``level[i]`` is the depth
62
+ of node i, and ``parent`` is a sparse table where parent[0][i] is the direct parent
63
+ of node i.
68
64
69
65
>>> # Consider a simple tree:
70
66
>>> # 1
71
67
>>> # / \\
72
68
>>> # 2 3
73
- >>> # With levels: level[1]=0, level[2]=1, level[3]=1 and parent[0]=[0,0,1, 1]
69
+ >>> # With levels: level[1]=0, level[2]=1, level[3]=1 and parent[0]=[0, 0, 1, 1]
74
70
>>> level = [-1, 0, 1, 1] # index 0 is dummy
75
71
>>> parent = [[0, 0, 1, 1]] + [[0, 0, 0, 0] for _ in range(19)]
76
72
>>> lowest_common_ancestor(2, 3, level, parent)
77
73
1
78
- >>> # LCA of a node with itself is itself.
79
74
>>> lowest_common_ancestor(2, 2, level, parent)
80
75
2
81
76
"""
@@ -93,7 +88,6 @@ def lowest_common_ancestor(
93
88
for i in range (18 , - 1 , - 1 ):
94
89
if parent [i ][u ] not in [0 , parent [i ][v ]]:
95
90
u , v = parent [i ][u ], parent [i ][v ]
96
- # Return the parent (direct ancestor) which is the LCA.
97
91
return parent [0 ][u ]
98
92
99
93
@@ -106,10 +100,10 @@ def breadth_first_search(
106
100
) -> tuple [list [int ], list [list [int ]]]:
107
101
"""
108
102
Run a breadth-first search (BFS) from the root node of the tree.
109
-
110
- Sets every node's direct parent (in parent[0]) and calculates the depth (level)
111
- of each node from the root.
112
-
103
+
104
+ This sets each node's direct parent (stored in parent[0]) and calculates the
105
+ depth (level) of each node from the root.
106
+
113
107
>>> # Consider a simple tree:
114
108
>>> # 1
115
109
>>> # / \\
@@ -138,27 +132,27 @@ def breadth_first_search(
138
132
139
133
def main () -> None :
140
134
"""
141
- Run a BFS to set node depths and parents in a sample tree,
142
- then create the sparse table and compute several lowest common ancestors.
143
-
135
+ Run a BFS to set node depths and parents in a sample tree, then create the
136
+ sparse table and compute several lowest common ancestors.
137
+
144
138
The sample tree used is:
145
139
146
- 1
147
- / | \
148
- 2 3 4
149
- / / \\ \\
150
- 5 6 7 8
151
- / \\ | / \\
152
- 9 10 11 12 13
153
-
140
+ 1
141
+ / | \
142
+ 2 3 4
143
+ / / \\ \\
144
+ 5 6 7 8
145
+ / \\ | / \\
146
+ 9 10 11 12 13
147
+
154
148
The expected lowest common ancestors are:
155
149
- LCA(1, 3) --> 1
156
150
- LCA(5, 6) --> 1
157
151
- LCA(7, 11) --> 3
158
152
- LCA(6, 7) --> 3
159
153
- LCA(4, 12) --> 4
160
154
- LCA(8, 8) --> 8
161
-
155
+
162
156
To test main() without it printing to the console, we capture the output.
163
157
164
158
>>> import sys
@@ -174,9 +168,7 @@ def main() -> None:
174
168
True
175
169
"""
176
170
max_node = 13
177
- # initializing with 0; extra space is allocated.
178
171
parent = [[0 for _ in range (max_node + 10 )] for _ in range (20 )]
179
- # initializing with -1 which means every node is unvisited.
180
172
level = [- 1 for _ in range (max_node + 10 )]
181
173
graph : dict [int , list [int ]] = {
182
174
1 : [2 , 3 , 4 ],
0 commit comments