解题思路:
二分+双模哈希
记忆出错的几个点:
- p和h数组都为long类型
- p[0] = 1必须加上
- 第一次计算所有h[i]时,新添加的数字必须从1开始,不能从0开始。
- 求固定长度为k的cur子串哈希值时,记得
long cur1 = ((h1[i][t]-h1[i][j-1]*p1[k])%mo1+mo1)%mo1;
当前计算的是字符串path[i]中下标为j-1开头,长度为k的字符串的哈希值,同时为了防止相减后出现负数,需要取模后加模再取模。
class Solution {
int m;
int max_len = 0;
long power = 13131;
long mo1 = 1e9+13,mo2 = 1e9+7;
vector<int>p1 = vector<int>(100000,0);
vector<int>p2 = vector<int>(100000,0);
public:
int longestCommonSubpath(int n, vector<vector<int>>& paths) {
m = paths.size();
vector<long>v;
vector<vector<long>>h1(m,v);
vector<vector<long>>h2(m,v);
int l = 0,r = INT_MAX;
for(int i = 0;i<m;i++){
int len = paths[i].size();
r = min(r,len);
h1[i] = vector<long>(len+5,0);
h2[i] = vector<long>(len+5,0);
for(int j = 0;j<len;j++){
//这里的+1对应上述易错点3
h1[i][j+1] = (h1[i][j]*power+paths[i][j]+1)%mo1;
h2[i][j+1] = (h2[i][j]*power+paths[i][j]+1)%mo2;
}
}
p1[0] = 1;
p2[0] = 1;
for(int i = 0;i<r;i++){
p1[i+1] = p1[i]*power%mo1;
p2[i+1] = p2[i]*power%mo2;
}
while(l<r){
int mid = (l+r+1)>>1;
if(func(mid,paths,h1,h2)){
l = mid;
}else{
r = mid-1;
}
}
return r;
}
private:
bool func(int k,vector<vector<int>>& paths,vector<vector<long>>& h1,vector<vector<long>>& h2){
unordered_set<long>info1,info2,info3,info4;
for(int i = 0;i<m;i++){
if(i != 0 && info1.size() == 0){
return false;
}
int len = paths[i].size();
if(len<k) return false;
for(int j = 1;j+k-1<=len;j++){
int t = j+k-1;
long cur1 = ((h1[i][t]-h1[i][j-1]*p1[k])%mo1+mo1)%mo1;
long cur2 = ((h2[i][t]-h2[i][j-1]*p2[k])%mo2+mo2)%mo2;
if(i == 0){
info1.insert(cur1);
info2.insert(cur2);
}else{
if(info1.find(cur1) != info1.end() && info2.find(cur2) != info2.end()){
info3.insert(cur1);
info4.insert(cur2);
}
}
}
if(i != 0){
swap(info1,info3);
swap(info2,info4);
info3.clear();
info4.clear();
}
}
if(info1.size() == 0){
return false;
}else
return true;
}
};