-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
lowestcommonancestor.go
123 lines (103 loc) · 3 KB
/
lowestcommonancestor.go
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
// lowestcommonancestor.go
// description: Implementation of Lowest common ancestor (LCA) algorithm.
// detail:
// Let `T` be a tree. The LCA of `u` and `v` in T is the shared ancestor of `u` and `v`
// that is located farthest from the root.
// time complexity: O(n log n) where n is the number of vertices in the tree
// space complexity: O(n log n) where n is the number of vertices in the tree
// references: [cp-algorithms](https://cp-algorithms.com/graph/lca_binary_lifting.html)
// author(s) [Dat](https://github.com/datbeohbbh)
// see lowestcommonancestor_test.go for a test implementation.
package graph
type TreeEdge struct {
from int
to int
}
type ITree interface {
dfs(int, int)
addEdge(int, int)
GetDepth(int) int
GetDad(int) int
GetLCA(int, int) int
}
type Tree struct {
numbersVertex int
root int
MAXLOG int
depth []int
dad []int
jump [][]int
edges [][]int
}
func (tree *Tree) addEdge(u, v int) {
tree.edges[u] = append(tree.edges[u], v)
tree.edges[v] = append(tree.edges[v], u)
}
func (tree *Tree) dfs(u, par int) {
tree.jump[0][u] = par
tree.dad[u] = par
for _, v := range tree.edges[u] {
if v != par {
tree.depth[v] = tree.depth[u] + 1
tree.dfs(v, u)
}
}
}
func (tree *Tree) GetDepth(u int) int {
return tree.depth[u]
}
func (tree *Tree) GetDad(u int) int {
return tree.dad[u]
}
func (tree *Tree) GetLCA(u, v int) int {
if tree.GetDepth(u) < tree.GetDepth(v) {
u, v = v, u
}
for j := tree.MAXLOG - 1; j >= 0; j-- {
if tree.GetDepth(tree.jump[j][u]) >= tree.GetDepth(v) {
u = tree.jump[j][u]
}
}
if u == v {
return u
}
for j := tree.MAXLOG - 1; j >= 0; j-- {
if tree.jump[j][u] != tree.jump[j][v] {
u = tree.jump[j][u]
v = tree.jump[j][v]
}
}
return tree.jump[0][u]
}
func NewTree(numbersVertex, root int, edges []TreeEdge) (tree *Tree) {
tree = new(Tree)
tree.numbersVertex, tree.root, tree.MAXLOG = numbersVertex, root, 0
tree.depth = make([]int, numbersVertex)
tree.dad = make([]int, numbersVertex)
for (1 << tree.MAXLOG) <= numbersVertex {
(tree.MAXLOG) += 1
}
(tree.MAXLOG) += 1
tree.jump = make([][]int, tree.MAXLOG)
for j := 0; j < tree.MAXLOG; j++ {
tree.jump[j] = make([]int, numbersVertex)
}
tree.edges = make([][]int, numbersVertex)
for _, e := range edges {
tree.addEdge(e.from, e.to)
}
return tree
}
// For each node, we will precompute its ancestor above him, its ancestor two nodes above, its ancestor four nodes above, etc.
// Let's call `jump[j][u]` is the `2^j`-th ancestor above the node `u` with `u` in range `[0, numbersVertex)`, `j` in range `[0,MAXLOG)`.
// These information allow us to jump from any node to any ancestor above it in `O(MAXLOG)` time.
func LowestCommonAncestor(tree *Tree) {
// call dfs to compute depth from the root to each node and the parent of each node.
tree.dfs(tree.root, tree.root)
// compute jump[j][u]
for j := 1; j < tree.MAXLOG; j++ {
for u := 0; u < tree.numbersVertex; u++ {
tree.jump[j][u] = tree.jump[j-1][tree.jump[j-1][u]]
}
}
}