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 thelongest common subpath that is shared by every friend’s path, or _0if there is no common subpath at all.
A subpath of a path is a contiguous sequence of cities within that path.
Input: n =5, paths =[[_0_ ,1,2,3,4],[4,3,2,1,_0_]]Output: 1Explanation: The possible longest common subpaths are [0],[1],[2],[3], and [4]. All have a length of 1.
We want the longest subpath (contiguous segment) that appears in every path. We can use binary search on the possible length and check for each length if a common subpath exists using a rolling hash (Rabin-Karp) to efficiently compare subpaths.
classSolution {
public:int longestCommonSubpath(int n, vector<vector<int>>& paths) {
int left =0, right = INT_MAX;
for (auto& p : paths) right = min(right, (int)p.size());
constlonglong mod = (1LL<<61) -1, base =100007;
auto check = [&](int len) ->bool {
unordered_set<longlong> s;
for (int i =0; i < paths.size(); ++i) {
unordered_set<longlong> cur;
longlong h =0, pow =1;
for (int j =0; j < len; ++j) h = (h * base + paths[i][j]) % mod, pow = (pow * base) % mod;
cur.insert(h);
for (int j = len; j < paths[i].size(); ++j) {
h = (h * base - paths[i][j-len] * pow % mod + mod) % mod;
h = (h + paths[i][j]) % mod;
cur.insert(h);
}
if (i ==0) s = cur;
else {
unordered_set<longlong> tmp;
for (auto x : cur) if (s.count(x)) tmp.insert(x);
s = tmp;
}
if (s.empty()) return false;
}
return!s.empty();
};
while (left < right) {
int mid = (left + right +1) /2;
if (check(mid)) left = mid;
else right = mid -1;
}
return left;
}
};
classSolution {
publicintlongestCommonSubpath(int n, int[][] paths) {
int left = 0, right = Integer.MAX_VALUE;
for (int[] p : paths) right = Math.min(right, p.length);
long mod = (1L << 61) - 1, base = 100007;
java.util.function.IntPredicate check = len -> {
Set<Long> s =new HashSet<>();
for (int i = 0; i < paths.length; i++) {
Set<Long> cur =new HashSet<>();
long h = 0, pow = 1;
for (int j = 0; j < len; j++) {
h = (h * base + paths[i][j]) % mod;
pow = (pow * base) % mod;
}
cur.add(h);
for (int j = len; j < paths[i].length; j++) {
h = (h * base - paths[i][j-len]* pow % mod + mod) % mod;
h = (h + paths[i][j]) % mod;
cur.add(h);
}
if (i == 0) s = cur;
else {
Set<Long> tmp =new HashSet<>();
for (long x : cur) if (s.contains(x)) tmp.add(x);
s = tmp;
}
if (s.isEmpty()) returnfalse;
}
return!s.isEmpty();
};
while (left < right) {
int mid = (left + right + 1) / 2;
if (check.test(mid)) left = mid;
else right = mid - 1;
}
return left;
}
}
classSolution {
funlongestCommonSubpath(n: Int, paths: Array<IntArray>): Int {
var left = 0var right = paths.minOf { it.size }
val mod = (1L shl 61) - 1val base = 100007Lfuncheck(len: Int): Boolean {
var s: Set<Long>? = nullfor (i in paths.indices) {
val cur = mutableSetOf<Long>()
var h = 0Lvar pow = 1Lfor (j in0 until len) {
h = (h * base + paths[i][j]) % mod
pow = (pow * base) % mod
}
cur.add(h)
for (j in len until paths[i].size) {
h = (h * base - paths[i][j-len] * pow % mod + mod) % mod
h = (h + paths[i][j]) % mod
cur.add(h)
}
s = if (i ==0) cur else s!!.intersect(cur)
if (s.isEmpty()) returnfalse }
return s!!.isNotEmpty()
}
while (left < right) {
val mid = (left + right + 1) / 2if (check(mid)) left = mid else right = mid - 1 }
return left
}
}
classSolution:
deflongestCommonSubpath(self, n: int, paths: list[list[int]]) -> int:
defcheck(length: int) -> bool:
mod, base = (1<<61) -1, 100007 s = set()
for i, path in enumerate(paths):
cur = set()
h, powb =0, 1for j in range(length):
h = (h * base + path[j]) % mod
powb = (powb * base) % mod
cur.add(h)
for j in range(length, len(path)):
h = (h * base - path[j-length] * powb % mod + mod) % mod
h = (h + path[j]) % mod
cur.add(h)
if i ==0:
s = cur
else:
s &= cur
ifnot s:
returnFalsereturn bool(s)
left, right =0, min(len(p) for p in paths)
while left < right:
mid = (left + right +1) //2if check(mid):
left = mid
else:
right = mid -1return left
impl Solution {
pubfnlongest_common_subpath(_n: i32, paths: Vec<Vec<i32>>) -> i32 {
letmut left =0;
letmut right = paths.iter().map(|p| p.len()).min().unwrap();
let mod_ = (1u64<<61) -1;
let base =100_007u64;
let check =|len: usize| -> bool {
letmut s = std::collections::HashSet::new();
for (i, path) in paths.iter().enumerate() {
letmut cur = std::collections::HashSet::new();
let (mut h, mut pow) = (0u64, 1u64);
for j in0..len {
h = (h * base + path[j] asu64) % mod_;
pow = (pow * base) % mod_;
}
cur.insert(h);
for j in len..path.len() {
h = (h * base + mod_ - (path[j-len] asu64* pow % mod_)) % mod_;
h = (h + path[j] asu64) % mod_;
cur.insert(h);
}
if i ==0 {
s = cur;
} else {
s = s.intersection(&cur).cloned().collect();
}
if s.is_empty() { returnfalse; }
}
!s.is_empty()
};
while left < right {
let mid = (left + right +1) /2;
if check(mid) {
left = mid;
} else {
right = mid -1;
}
}
left asi32 }
}