[关键字]:字符串 后缀数组
[题目大意]:问两个字符串的最长公共子串。
//=====================================================================================================
[分析]:首先将两个字符连在一起,并在中间加入'$'分割,然后两个串的最长公共字串就变成了所有后缀的最长公共前缀。这时就要用到height数组,因为任意两个后缀的公共前缀必定是某些height值中的最小值,而这个值如果最大则一定是height中的最大值。在此题中还要注意height最大一定要在两个值所代表的后缀分属不同的字符串地前提下。
[代码]:
View Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define MAXN 1000001
using namespace std;
char s[MAXN*3];
int n,sa[MAXN],top[MAXN],tmp[MAXN],h[MAXN],rank[MAXN];
int makesa()
{
int i,j,len,m;
m=(n<256?256:n);
memset(top,0,m*sizeof(int));
for (i=0;i<n;i++) top[rank[i]=s[i] & 0xff]++;
for (i=1;i<m;i++) top[i]+=top[i-1];
for (i=0;i<n;i++) sa[--top[rank[i]]]=i;
for (len=1;len<n;len<<=1)
{
for (i=0;i<n;i++)
{
j=sa[i]-len;
if (j<0) j+=n;
tmp[top[rank[j]]++]=j;
}
sa[tmp[top[0]=0]]=j=0;
for (i=1;i<n;i++)
{
if (rank[tmp[i]]!=rank[tmp[i-1]] ||
rank[tmp[i]+len]!=rank[tmp[i-1]+len]) top[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rank,sa,n*sizeof(int));
memcpy(sa,tmp,n*sizeof(int));
if (j>=n-1) break;
}
return 0;
}
int lcp()
{
int i,j,k;
//printf("%d %d\n",rank[0],sa[0]);
for (j=rank[h[i=k=0]=0];i<n-1;i++,k++)
while (k>=0 && s[i]!=s[sa[j-1]+k])
h[j]=(k--),j=rank[sa[j]+1];
return 0;
}
int main()
{
gets(s);
int l1=strlen(s);
s[l1]='$';
gets(s+l1+1);
n=strlen(s);
s[n++]='$';
makesa();
lcp();
int b=0;
//for (int i=0;i<n;i++) printf("%d ",h[i]);
for (int i=1;i<n;i++)
{
if ((sa[i]<l1 && sa[i-1]>l1) || (sa[i]>l1 && sa[i-1]<l1))
if (h[i]>b) b=h[i];
}
printf("%d\n",b);
system("pause");
return 0;
}