题面
【题目描述】
F
a
r
m
e
r
J
o
h
n
Farmer John
FarmerJohn为他的奶牛们订阅了
G
o
o
d
H
o
o
v
e
s
k
e
e
p
i
n
g
Good Hooveskeeping
GoodHooveskeeping杂志,因此他们在谷仓等待挤奶期间,可以有足够的文章可供阅读。不幸的是,最新一期的文章包含一篇关于如何烹制完美牛排的不恰当的文章,
F
J
FJ
FJ不愿让他的奶牛们看到这些内容。
F J FJ FJ已经根据杂志的所有文字,创建了一个字符串 $S $( S S S 的长度保证不超过 1 0 6 10^6 106 ),他想删除其中的子串 T T T ,他将删去 S S S 中第一次出现的子串 T T T,然后不断重复这一过程,直到 S S S 中不存在子串 T T T。
注意:每次删除一个子串后,可能会出现一个新的子串 T T T (说白了就是删除之后,两端的字符串有可能会拼接出来一个新的子串 T T T)。
【输入格式】
第一行是字符串
S
S
S ,第二行输入字符串
T
T
T ,保证
S
S
S 的长度大于等于 T 的长度,
S
S
S 和
T
T
T 都只由小写字母组成。
【输出格式】
输出经过处理后的字符串,保证处理后的字符串不会为空串
算法分析
单模式串的匹配通常采用KMP算法。
但是本题在匹配的同时,会进行删除,但是删除的部分肯定是已经匹配了的部分,所以可以用两个栈来记录。
一个栈st[],记录未匹配成功的字符
一个栈num[],记录每个字符S[i]对应匹配的T[j]中的j
这样,当匹配成功后,可以对删除子串的前一个S[i],找到对应的T[j],继续执行KMP算法。
参考程序
#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
char S[N],T[N];
int nxt[N];
char st[N]; //栈
int top;
int num[N];
void pre() //预处理nxt数组
{
int j;
nxt[1]=j=0; //初始化
int lent=strlen(T+1);
for(int i=1;i<lent;i++)
{
while(j>0&&T[i+1]!=T[j+1]) j=nxt[j];
if(T[j+1]==T[i+1]) j++;
nxt[i+1]=j;
}
}
void kmp()
{
int lent=strlen(T+1);
int lens=strlen(S+1);
int j=0;
for(int i=0;i<lens;i++)
{
while(j>0&&S[i+1]!=T[j+1]) j=nxt[j];
if(S[i+1]==T[j+1]) j++;
st[++top]=S[i+1]; //未匹配的入栈
num[top]=j; //记录每个i对应的j
if(j==lent) //匹配成功,则将整个匹配部分出栈
{
top-=lent;
if(top==0) j=0; //栈空
else j=num[top]; //从当前st[top]字符对应的j,即num[top],继续往后匹配
}
}
for(int i=1;i<=top;i++)
printf("%c",st[i]);
}
int main()
{
scanf("%s%s",S+1,T+1);
pre();
kmp();
return 0;
}