-
Notifications
You must be signed in to change notification settings - Fork 61
Expand file tree
/
Copy path1923-longest-common-subpath.js
More file actions
148 lines (121 loc) · 3.95 KB
/
1923-longest-common-subpath.js
File metadata and controls
148 lines (121 loc) · 3.95 KB
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
142
143
144
145
146
147
148
/**
* 1923. Longest Common Subpath
* https://leetcode.com/problems/longest-common-subpath/
* Difficulty: Hard
*
* There is a country of n cities numbered from 0 to n - 1. In this country, there is a road
* connecting every pair of cities.
*
* There are m friends numbered from 0 to m - 1 who are traveling through the country. Each one
* of them will take a path consisting of some cities. Each path is represented by an integer
* array that contains the visited cities in order. The path may contain a city more than once,
* but the same city will not be listed consecutively.
*
* Given an integer n and a 2D integer array paths where paths[i] is an integer array representing
* the path of the ith friend, return the length of the longest common subpath that is shared
* by every friend's path, or 0 if there is no common subpath at all.
*
* A subpath of a path is a contiguous sequence of cities within that path.
*/
/**
* @param {number} n
* @param {number[][]} paths
* @return {number}
*/
var longestCommonSubpath = function(n, paths) {
if (paths.length === 0) return 0;
paths.sort((a, b) => a.length - b.length);
let left = 0;
let right = paths[0].length;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (checkCommonSubpathExists(paths, mid)) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return right;
};
function checkCommonSubpathExists(paths, length) {
if (length === 0) return true;
const firstPath = paths[0];
if (firstPath.length < length) return false;
const prime = 1000000007;
const base = 100003;
let highestPower = 1;
for (let i = 0; i < length - 1; i++) {
highestPower = (highestPower * base) % prime;
}
let hashToPositions = new Map();
let hash = 0;
for (let i = 0; i < length; i++) {
hash = (hash * base + firstPath[i]) % prime;
}
if (!hashToPositions.has(hash)) {
hashToPositions.set(hash, []);
}
hashToPositions.get(hash).push(0);
for (let i = 1; i <= firstPath.length - length; i++) {
hash = ((hash - firstPath[i - 1] * highestPower % prime + prime)
% prime * base + firstPath[i + length - 1]) % prime;
if (!hashToPositions.has(hash)) {
hashToPositions.set(hash, []);
}
hashToPositions.get(hash).push(i);
}
for (let pathIdx = 1; pathIdx < paths.length; pathIdx++) {
const path = paths[pathIdx];
if (path.length < length) return false;
const newHashToPositions = new Map();
hash = 0;
for (let i = 0; i < length; i++) {
hash = (hash * base + path[i]) % prime;
}
if (hashToPositions.has(hash)) {
const positions = hashToPositions.get(hash);
for (const pos of positions) {
let isMatch = true;
for (let j = 0; j < length; j++) {
if (firstPath[pos + j] !== path[j]) {
isMatch = false;
break;
}
}
if (isMatch) {
if (!newHashToPositions.has(hash)) {
newHashToPositions.set(hash, []);
}
newHashToPositions.get(hash).push(pos);
break;
}
}
}
for (let i = 1; i <= path.length - length; i++) {
hash = ((hash - path[i - 1] * highestPower % prime + prime)
% prime * base + path[i + length - 1]) % prime;
if (hashToPositions.has(hash)) {
const positions = hashToPositions.get(hash);
for (const pos of positions) {
let isMatch = true;
for (let j = 0; j < length; j++) {
if (firstPath[pos + j] !== path[i + j]) {
isMatch = false;
break;
}
}
if (isMatch) {
if (!newHashToPositions.has(hash)) {
newHashToPositions.set(hash, []);
}
newHashToPositions.get(hash).push(pos);
break;
}
}
}
}
if (newHashToPositions.size === 0) return false;
hashToPositions = newHashToPositions;
}
return hashToPositions.size > 0;
}