您的位置:首页 > 其它

HDU1403 Longest Common Substring

2014-07-09 14:02 302 查看

Longest Common Substring

Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 3851 Accepted Submission(s): 1443



[align=left]Problem Description[/align]
Given two strings, you have to tell the length of the Longest Common Substring of them.

For example:

str1 = banana

str2 = cianaic

So the Longest Common Substring is "ana", and the length is 3.

[align=left]Input[/align]
The input contains several test cases. Each test case contains two strings, each string will have at most 100000 characters. All the characters are in lower-case.

Process to the end of file.

[align=left]Output[/align]
For each test case, you have to tell the length of the Longest Common Substring of them.

[align=left]Sample Input[/align]

banana
cianaic


[align=left]Sample Output[/align]

3


[align=left]Author[/align]
Ignatius.L

后缀数组的模板题。。。代码加了注释

#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=1000010;
int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
int sa[MAXN],r[MAXN<<1];
int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
//对长度为1的字符串排序
for(i=0;i<m;i++)
ws[i]=0;
for(i=0;i<n;i++)    //统计各个字符的数量
ws[x[i]=r[i]]++;
for(i=1;i<m;i++)    //统计不大于i的字符的数量
ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)
sa[--ws[x[i]]]=i;   //从字符串尾部开始排名,求后缀,字符串长字典序大
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++)  //y里保存的是第二关键字的排序结果,结合图后j很弱字符串的第二关键都是0
y[p++]=i;
for(i=0;i<n;i++)    //第二关键字的排序可以直接根据第一次排序的sa来看
if(sa[i]>=j)    //sa里存的是排名第i的是谁
y[p++]=sa[i]-j;
for(i=0;i<n;i++)    //x保存了rank的值,用y又是运用了第二关键字排序的结果,也是基数排序的要求
wv[i]=x[y[i]];  //y[i]相当于是进行了第二关键字排序的字符的下标
//对第一关键字基数排序
for(i=0;i<m;i++)
ws[i]=0;
for(i=0;i<n;i++)
ws[wv[i]]++;
for(i=1;i<m;i++)
ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)
sa[--ws[wv[i]]]=y[i];       //y[i]才是下标
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;//rank值相同位置也要相同
}
return;
}
int rank[MAXN],height[MAXN];
void callheight(int *r,int *sa,int n)
{
int i,j,k=0;
for (i=1;i<=n;++i)  //rank里记录的是排名
rank[sa[i]]=i;
for (i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];++k);    //那个结论height[rank[i]]>=height[rank[i-1]]-1
return; //k==0不动,不为0就要减一
}
char s[MAXN<<1];
int main()
{
int i;
while(scanf("%s",s)!=EOF)
{
int len=strlen(s);
s[len]='0'; //要将两个串合成一条串,然后求他子串的最长公共前缀就行
int len1=len;
scanf("%s",s+1+len);
len=strlen(s);
for(i=0;i<len;i++)
r[i]=s[i];
r[len]=0;
da(r,sa,len+1,300);
callheight(r,sa,len);
int ans=0;
for(i=2;i<=len;i++)
{
if(ans<height[i])
{
if((sa[i]>len1&&sa[i-1]<len1)||(sa[i]<len1&&sa[i-1]>len1))  //sa记录的是排名第几的是谁
ans=height[i];
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: