版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意:给你两个字符串s 和 t,让你找一个最长的字串,它是s的前缀 ,也是t的后缀,如果没有输出0,否则输出这个字符串和最大的长度。
思路:很基础的KMP,一开始没转过来这个弯,主要是对KMP算法中f[ ] 数组的含义不是很清楚。
f[ i ] 的含义 为 B中 以 i 结尾的子串 与 模式串 A的前缀能够匹配的最长长度。
所以本题中,以s为模式串,t为文本串 求出 f[ ] 数组即可,f[n] 即为所求子串的最大长度。
AC Code:
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<sstream>
#include<algorithm>
using namespace std;
#define read(x) scanf("%d",&x)
#define Read(x,y) scanf("%d%d",&x,&y)
#define sRead(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define gc(x) scanf(" %c",&x);
#define mmt(x,y) memset(x,y,sizeof x)
#define write(x) printf("%d\n",x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod 998244353
#define pdd pair<double,double>
const int N = 1000;
const int M= 1e6;
char s[M+5];
char c[M+5];
int Next[M+5];
int f[M+5];
void kmp_pre(int m){
int i = 0,j = Next[0] = -1;
while(i < m){
while(j!= -1&&s[i] != s[j]) j = Next[j];
Next[++i] = ++j;
}
}
void kmp(int n,int m)
{
int j = 0,i = 0;
while(i < n){
while(j!=-1&&s[j]!=c[i]) j = Next[j];
f[++i] = ++j;
//if(j >=m) j = Next[j];
}
}
int main()
{
while(~scanf("%s%s",s,c)){
mmt(Next,0);
mmt(f,0);
int n = strlen(s);
int m = strlen(c);
kmp_pre(n);
kmp(m,n);
int MAX = f[m];
if(MAX == 0){
puts("0");
}else {
cout<<(c+m - MAX);
cout<<" "<<MAX<<endl;
}
}
}
扩展KMP
Next[ ] 数组的含义 :
Next[ i ] 含义是A中以 i 结尾的后缀与前缀匹配最大的长度。
extend[ ] 数组的含义 :extend[i] 的含义 是 B 中以 i 结尾的后缀与A字符串前缀匹配的最大长度
所以这个题目只需要求出 extend数组 ,对于 每一个位置 i 来说 , extend[i] + i == len(B) ,说明 B存在长度为 extend[i] 的 后缀 与 A 中长度为 extend[i] 的前缀 匹配。那么只需要从左向右遍历一遍,检查到跳出即可。
AC Code:
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<sstream>
#include<algorithm>
using namespace std;
#define read(x) scanf("%d",&x)
#define Read(x,y) scanf("%d%d",&x,&y)
#define sRead(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define gc(x) scanf(" %c",&x);
#define mmt(x,y) memset(x,y,sizeof x)
#define write(x) printf("%d\n",x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod 998244353
#define pdd pair<double,double>
const int N = 1000;
const int M= 1e6+5;
char s[M+5],t[M+5];
int Next[M+5];
int extend[M+5];
void pre_EKMP(char x[],int m,int Next[])
{
Next[0]=m;
int j=0;
while(j+1<m && x[j]==x[j+1]) j++;
Next[1]=j;
int k=1;
for(int i=2;i<m;i++)
{
int p=Next[k]+k-1;
int L=Next[i-k];
if(i+L<p+1)Next[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<m && x[i+j]==x[j])j++;
Next[i]=j;
k=i;
}
}
}
void EKMP(char x[],int m,char y[],int n,int Next[],int extend[])
{
pre_EKMP(x,m,Next);
int j=0;
while(j<n && j<m && x[j]==y[j]) j++;
extend[0]=j;
int k=0;
for(int i=1;i<n;i++)
{
int p=extend[k]+k-1;
int L=Next[i-k];
if(i+L<p+1)
extend[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<n && j<m && y[i+j]==x[j]) j++;
extend[i]=j;
k=i;
}
}
}
int main()
{
while(~scanf("%s%s",s,t)){
mmt(Next,0);
mmt(extend,0);
int m,n;
m = strlen(s);
n = strlen(t);
EKMP(s,m,t,n,Next,extend);//求出 extend[]
// for(int i = 0;i < n;++i) cout<<extend[i]<<" ";
int k = -1;
for(int i = 0;i < n;++i){
if(extend[i] + i == n)//遍历 ,找到跳出
{k = i;break;}
}
// continue;
if(k == -1) {
puts("0");
continue;
}
cout<<(t + k)<<" ";
cout<<extend[k]<<endl;
}
}