请读者在阅读前充分理解KMP与其失配函数的意义。
题目描述
原题来自:USACO 2015 Feb. Silver
给出两个字符串 S 和 T,每次从前往后找到 S 的一个子串 A=T 并将其删除,空缺位依次向前补齐,重复上述操作多次,直到 S 串中不含 T 串。输出最终的 S 串。
输入格式
第一行包含一个字符串 S,第二行包含一个字符串 T。
输出格式
输出处理后的 S 串。
样例
输入
whatthemomooofun
moo
输出
whatthefun
数据范围与提示
对于全部数据,
1
≤
∣
T
∣
≤
∣
S
∣
≤
1
0
6
1\le |T|\le |S|\le 10^6
1≤∣T∣≤∣S∣≤106,保证字符串中只出现小写字母。
代码
#include<bits/stdc++.h>
const int M=1e7;
char a[M],b[M];int n,m,s[M],st[M],top=0;
using namespace std;
int f[M];
void getfail(char *a,int *f){
int j=0;
f[0]=f[1]=0;
for (int i=1;i<m;i++){
while(j and a[i+1]!=a[j+1]) j=f[j];
if (a[i+1]==a[j+1]) j++;
f[i+1]=j;
}
}
int main(){
scanf("%s",a+1);scanf("%s",b+1);
n=strlen(a+1);m=strlen(b+1);
getfail(b,f);
int j=0;
for (int i=0;i<n;i++){
while (j and a[i+1]!=b[j+1]) j=f[j];
if (a[i+1]==b[j+1]) j++;
s[i]=j;
st[++top]=i;
if (j==m){
top-=m;
j=s[st[top]];
}
}
for (int i=1;i<=top;i++)
cout<<a[st[i]+1];
return 0;
}
分析
getfail是求失配数字的函数,与其他的KMP并无区别,在这里不过多赘述。
for (int i=0;i<n;i++){
while (j and a[i+1]!=b[j+1]) j=f[j];
if (a[i+1]==b[j+1]) j++;
s[i]=j;
st[++top]=i;
if (j==m){
top-=m;
j=s[st[top]];
}
}
匹配有点不同,这里多了两个数组:
1.s
是一个记录数组,用于记录主串在匹配i处时,匹配串匹配了j个元素
2.st
是手打栈,而top
是栈顶下标,存放主串的下标
在匹配时,若成功匹配,回到之前的j
比如样例:
j值的变化:3->2,3->0
for (int i=1;i<=top;i++)
cout<<a[st[i]+1];
由于下标从1开始,所以+1;