求解最长公共字串使用二分+字符串哈希
二分得到长度M,然后分别哈希两个字符串长度为M的子串,看两个字符串的哈希值是否有相等的,然后不断二分直到长度最大。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const long long B = 1e8+7;
const int MAX = 100010;
int n,m;
char s1[MAX],s2[MAX];
long long base[MAX],hash[MAX];
bool check(int len){
long long tmp = 0;
for(int i=0; i<len; i++)
tmp = tmp * B + s1[i];
hash[0] = tmp;
for(int i=0; i<=n-len; i++)
hash[i+1] = hash[i]*B + s1[i+len] - s1[i]*base[len];//通过一个哈希值求所有长度为len的字串的哈希值(B进制的数字)
sort(hash, hash+n-len+1);//二分查找先排序
long long Hash = 0;
for(int i=0; i<len; i++) Hash = Hash*B + s2[i];
for(int i=0; i<m-len+1; i++){
if(binary_search(hash, hash+n-len+1, Hash)) return true;
Hash = Hash*B + s2[i+len]-s2[i]*base[len];
}
return false;
}
int main(){
base[0] = 1;
for(int i=1; i<MAX; i++) base[i] = base[i-1]*B;
scanf("%s",s1);
scanf("%s",s2);
n = strlen(s1);
m = strlen(s2);
int ans = -1;
int l = 0, r = min(n, m);
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid)){//mid可行那么向右查找是否有更大的答案
l = mid + 1;
ans = mid;
}
else r = mid - 1;
}
printf("%d\n",ans);
}