题意:
给出两个最长长为1e5的字符串,求他们的最长公共子串长度。
思路:
分别将两个字符串预处理出hash值,二分【1-min(lens,lent)】的长度,check函数中每次将长度为mid的hash值记录并检查是否符合条件,是则下边界右移,否则上边界左移。复杂度O(nlogn)
代码:
#include<stdio.h>
#include<vector>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N =100000+5;
char s[N],t[N];
int lens,lent;
ull base=233;
ull p[N],hs[N],ht[N];
ull geths(int l,int r)
{
return hs[r]-p[r-l+1]*hs[l-1];
}
ull getht(int l,int r)
{
return ht[r]-p[r-l+1]*ht[l-1];
}
int check(int len)
{
vector<ull>mp;
for(int i=1; i<=lens-len+1; i++)
{
ull tmp=geths(i,i+len-1);
mp.push_back(tmp);
}
sort(mp.begin(),mp.end());
for(int i=1; i<=lent-len+1; i++)
{
ull tmp=getht(i,i+len-1);
if(binary_search(mp.begin(),mp.end(),tmp)) return 1;
}
return 0;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
p[0]=1;
for(int i=1; i<N; i++) p[i]=p[i-1]*base;
while(~scanf("%s%s",s+1,t+1))
{
lens=strlen(s+1);
lent=strlen(t+1);
for(int i=1; i<=lens; i++)
{
hs[i]=hs[i-1]*base+s[i]-'a';
}
for(int i=1; i<=lent; i++)
{
ht[i]=ht[i-1]*base+t[i]-'a';
}
int l=1,r=min(lens,lent),mid;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid)) l=mid+1;
else r=mid-1;
}
printf("%d\n",r);
}
}