分析: 给出两个字符串S1,S2,求出一个最长子串(既是S1 的前缀又是S2的后缀),一开始是打算用完整的扩展KMP去做,但是结果迷之WA,后来改成合并字符串,把S2接S1后面,然后获取整个字符串的Next数组来做。
题解:
- 从strlen(s1)的地方开始遍历Next数组,这个时候找S[strlen(s1)]到末尾的后缀与S的前缀的最大匹配,就是题目要求的意思:
L = strlen(s1); for(int i = L; i< l1; i++) { int now = Next[i]; if(i+Next[i] == l1)//如果长度和整个长度相等,那么说明s2的【后缀】和s1的前缀匹配上 { ans = max(ans , now ) ;//取最大值 } } ans = ans >= L ? L : ans ;//不超过s1的长度
- Next数组求法
-
const int Max=50000+10; int Next[Max*2]; //ex数组即为extend数组 void GETNext(char *str) { Clear(Next); int i=0,j,po,len=strlen(str); Next[0]=len;//初始化Next[0] while(str[i]==str[i+1]&&i+1<len)//计算Next[1] i++; Next[1]=i; po=1;//初始化po的位置 for(i=2;i<len;i++) { if(Next[i-po]+i<Next[po]+po)//第一种情况,可以直接得到Next[i]的值 Next[i]=Next[i-po]; else//第二种情况,要继续匹配才能得到Next[i]的值 { j=Next[po]+po-i; if(j<0) j=0;//如果i>po+Next[po],则要从头开始匹配 while(i+j<len&&str[j]==str[j+i])//计算Next[i] j++; Next[i]=j; po=i;//更新po的位置 } } }
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#define Clear(a) memset(a, 0, sizeof(a))
using namespace std;
const int Max=50000+10;
int Next[Max*2]; //ex数组即为extend数组
void GETNext(char *str)
{
Clear(Next);
int i=0,j,po,len=strlen(str);
Next[0]=len;//初始化Next[0]
while(str[i]==str[i+1]&&i+1<len)//计算Next[1]
i++;
Next[1]=i;
po=1;//初始化po的位置
for(i=2;i<len;i++)
{
if(Next[i-po]+i<Next[po]+po)//第一种情况,可以直接得到Next[i]的值
Next[i]=Next[i-po];
else//第二种情况,要继续匹配才能得到Next[i]的值
{
j=Next[po]+po-i;
if(j<0) j=0;//如果i>po+Next[po],则要从头开始匹配
while(i+j<len&&str[j]==str[j+i])//计算Next[i]
j++;
Next[i]=j;
po=i;//更新po的位置
}
}
}
char s1[Max*2];
char s2[Max*2];
int main()
{
while(~scanf("%s", &s1) )
{
int L = strlen(s1);
scanf("%s", s1+L);
GETNext(s1);
int l1 = strlen(s1);
int ans = -1;
for(int i = L;i<l1;i++)
{
int now = Next[i];
if(i+Next[i] == l1)
{
ans = max(ans , now ) ;
}
}
ans = ans >= L ? L : ans ;
for(int i=0;i<ans;i++)
{
cout << s1[i];
}
if(ans>=0)
{
cout << " " << ans << endl;
}
else
cout << 0 << endl;
}
return 0;
}