一个国家由 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] 中同一个城市不会连续重复出现。
思路:二分答案+滚动hash。
class Solution {
private static int mod1 = 1000000007;
private static int mod2 = 1000000009;
private static int base1, base2;
public int longestCommonSubpath(int n, int[][] paths) {
int ans = 0;
int m = paths.length;
int len = 1000005;
Random random = new Random();
base1 = random.nextInt(10000000 - 1000000 + 1) + 1000000;
base2 = random.nextInt(10000000 - 1000000 + 1) + 1000000;
System.out.println(base1 + " " + base2);
for (int i = 0; i < m; i++)
len = Math.min(len, paths[i].length);
int l = 1, r = len;
while (l <= r) {
int mid = (l + r) / 2;
if (check(n, paths, mid)) {
ans = mid;
l = mid + 1;
} else
r = mid - 1;
}
return ans;
}
private static boolean check(int n, int[][] arr, int len) {
int m = arr.length;
long mul1 = 1, mul2 = 1;
for (int i = 1; i <= len; i++) {
mul1 = mul1 * base1 % mod1;
mul2 = mul2 * base2 % mod2;
}
Set<Long> s = new HashSet<>();
for (int i = 0; i < m; i++) {
long hash1 = 0, hash2 = 0;
for (int j = 0; j < len; j++) {
hash1 = (hash1 * base1 + arr[i][j]) % mod1;
hash2 = (hash2 * base2 + arr[i][j]) % mod2;
}
Set<Long> t = new HashSet<>();
long val = hash(hash1, hash2);
if (i == 0 || s.contains(val))
t.add(val);
for (int j = len; j < arr[i].length; j++) {
hash1 = ((hash1 * base1 % mod1 - (long) arr[i][j - len] * mul1 % mod1 + arr[i][j]) % mod1 + mod1) % mod1;
hash2 = ((hash2 * base2 % mod2 - (long) arr[i][j - len] * mul2 % mod2 + arr[i][j]) % mod2 + mod2) % mod2;
val = hash(hash1, hash2);
if (i == 0 || s.contains(val))
t.add(val);
}
if (t.isEmpty())
return false;
s.clear();
for (Long ss : t)
s.add(ss);
}
return true;
}
private static long hash(long hash1, long hash2) {
long val1 = String.valueOf(hash1).hashCode();
long val2 = String.valueOf(hash2).hashCode();
return val1 << 16 ^ val2;
}
}