Skip to content

Commit c1aaa80

Browse files
authored
Create 1923-longest-common-subpath.js
1 parent 4c2916c commit c1aaa80

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

1923-longest-common-subpath.js

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* @param {number} n
3+
* @param {number[][]} paths
4+
* @return {number}
5+
*/
6+
const longestCommonSubpath = function(n, paths) {
7+
if (!paths.length) return 0
8+
let arr = paths[0]
9+
for (const path of paths) if (path.length < arr.length) arr = path
10+
return new Sam(arr).longestCommonSubpath(paths)
11+
};
12+
13+
class State {
14+
constructor(len, link, next) {
15+
this.len = len
16+
this.link = link
17+
this.next = new Map(next)
18+
this.ans = len
19+
this.revLink = []
20+
this.max = 0
21+
}
22+
}
23+
24+
/**
25+
* @param p {State}
26+
* @return boolean
27+
*/
28+
function dfs(p) {
29+
let hasNext = false
30+
for (const q of p.revLink) {
31+
hasNext = dfs(q) || hasNext
32+
}
33+
if (hasNext) p.max = p.len
34+
return p.max > 0
35+
}
36+
37+
class Sam {
38+
newState(len, link, next) {
39+
const state = new State(len, link, next)
40+
this.container.push(state)
41+
return state
42+
}
43+
44+
constructor(path) {
45+
this.container = []
46+
const root = this.newState(0, null)
47+
let last = root
48+
for (const x of path) {
49+
const cur = this.newState(last.len + 1, root)
50+
for (let p = last; p; p = p.link) {
51+
const q = p.next.get(x)
52+
if (!q) {
53+
p.next.set(x, cur)
54+
continue
55+
}
56+
if (q.len === p.len + 1) {
57+
cur.link = q
58+
} else {
59+
const clone = this.newState(p.len + 1, q.link, q.next)
60+
for (; p && p.next.get(x) === q; p = p.link) p.next.set(x, clone)
61+
cur.link = q.link = clone
62+
}
63+
break
64+
}
65+
last = cur
66+
}
67+
for (const state of this.container)
68+
if (state.link) state.link.revLink.push(state)
69+
}
70+
71+
visit(path) {
72+
for (const state of this.container) state.max = 0
73+
const root = this.container[0]
74+
let p = root
75+
let len = 0
76+
for (const x of path) {
77+
for (; ; p = p.link, len = p.len) {
78+
const q = p.next.get(x)
79+
if (q) {
80+
p = q
81+
p.max = Math.max(p.max, ++len)
82+
break
83+
}
84+
if (!p.link) break
85+
}
86+
}
87+
dfs(root)
88+
for (const state of this.container)
89+
state.ans = Math.min(state.ans, state.max)
90+
}
91+
92+
longestCommonSubpath(paths) {
93+
for (const path of paths) this.visit(path)
94+
let ans = 0
95+
for (const state of this.container) ans = Math.max(ans, state.ans)
96+
return ans
97+
}
98+
}

0 commit comments

Comments
 (0)