一个国家由 n 个编号为 0 到 n - 1 的城市组成。在这个国家里,每两个 城市之间都有一条道路连接。
总共有 m 个编号为 0 到 m - 1 的朋友想在这个国家旅游。他们每一个人的路径都会包含一些城市。每条路径都由一个整数数组表示,每个整数数组表示一个朋友按顺序访问过的城市序列。同一个城市在一条路径中可能 重复 出现,但同一个城市在一条路径中不会连续出现。
给你一个整数 n 和二维数组 paths ,其中 paths[i] 是一个整数数组,表示第 i 个朋友走过的路径,请你返回 每一个 朋友都走过的 最长公共子路径 的长度,如果不存在公共子路径,请你返回 0 。
一个 子路径 指的是一条路径中连续的城市序列。
示例 1:
输入:n = 5, paths = [[0,1,2,3,4],
[2,3,4],
[4,0,1,2,3]]
输出:2
解释:最长公共子路径为 [2,3] 。
示例 2:
输入:n = 3, paths = [[0],[1],[2]]
输出:0
解释:三条路径没有公共子路径。
示例 3:
输入:n = 5, paths = [[0,1,2,3,4],
[4,3,2,1,0]]
输出:1
解释:最长公共子路径为 [0],[1],[2],[3] 和 [4] 。它们长度都为 1 。
提示:
1 <= n <= 105
m == paths.length
2 <= m <= 105
sum(paths[i].length) <= 105
0 <= paths[i][j] < n
paths[i] 中同一个城市不会连续重复出现。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-common-subpath
class Solution {
public int longestCommonSubpath(int n, int[][] paths) {
int left = 1,right = getMin(paths);
Random rand = new Random();
long base = 135721;//100000 + rand.nextInt(1000000-100000+1);
long mod = Long.MAX_VALUE;
long muti = 0;
int ans = 0;
while(left<=right){
int mid = (left+right)/2;
muti = pow(base,mid,mod);
Set<Long> set = new HashSet<>();
for(int i=0 ; i<paths.length ; i++){
long hash = 0;
Set<Long> tmp = new HashSet<>();
for(int j=0 ; j<mid ; j++){
hash = (hash*base + paths[i][j])%mod;
}
if(i==0 || set.contains(hash)){
tmp.add(hash);
}
for(int j=mid ; j<paths[i].length ; j++){
hash = (hash*base + paths[i][j] - muti*paths[i][j-mid])%mod;
if(i==0 || set.contains(hash)){
tmp.add(hash);
}
}
set = tmp;
if(set.isEmpty()){
break;
}
}
if(set.isEmpty()){
right = mid-1;
} else{
left = mid+1;
ans = mid;
}
}
return ans;
}
int getMin(int[][] paths){
int min = paths[0].length;
for(int[] path : paths){
min = Math.min(path.length,min);
}
return min;
}
long pow(long base,long n,long mod){
long res = 1;
for(int i=0 ; i<n ; i++){
res = (res * base)%mod;
}
return res;
}
}