题意:
Farmer John为他的奶牛们订阅了Good Hooveskeeping杂志,因此他们在谷仓等待挤奶期间,可以有足够的文章可供阅读。不幸的是,最新一期的文章包含一篇关于如何烹制完美牛排的不恰当的文章,FJ不愿让他的奶牛们看到这些内容。
FJ已经根据杂志的所有文字,创建了一个字符串 SS ( SS 的长度保证不超过 10^6 ),他想删除其中的子串 TT ,他将删去 SS 中第一次出现的子串 TT ,然后不断重复这一过程,直到 SS 中不存在子串 TT 。
注意:每次删除一个子串后,可能会出现一个新的子串 TT (说白了就是删除之后,两端的字符串有可能会拼接出来一个新的子串 TT )。
输入格式:第一行是字符串 SS ,第二行输入字符串 TT ,保证 SS 的长度大于等于 TT 的长度, SS 和 TT 都只由小写字母组成。
输出格式:输出经过处理后的字符串,保证处理后的字符串不会为空串。
样例:
输入
whatthemomooofun moo
输出
whatthefun
题解:
字符串匹配的问题,想到 KMPKMP
在匹配过程中,如果匹配成功了,就将子串 BB 删除,可以证明,对之前不会产生影响
删了再加入,类似栈的操作,因此用栈维护上述操作过程中的字串即可:在 KMP 过程中,把遍历到的 ii(不是字符,而是下标)入栈,当匹配上 B 时,就把匹配的部分出栈,然后 j从栈顶的 i 所能匹配到的最大的位置开始(就是 f[i]
记录的值),继续做 KMP。
代码如下:
/*Keep on going Never give up*/
#include <bits/stdc++.h>
using namespace std;
#define MAX 0x7fffffff
#define int long long
const int mod = 1e9+7;
const int maxn = 1e6+1000;
char a[maxn],b[maxn];
int next1[maxn],lb,la,st[maxn],top,f[maxn];
// b串自我匹配:关键是找出自己的可能循环点:如abcabd:那么两个ab就有可能作为回溯的点,可能从这里往前匹配可以得解;不然就不用回溯,一直往前就好了;
void KMP(){
next1[1]=0;
for(int i=2,j=0;i<=lb;i++)
{
while(j!=0&&b[i]!=b[j+1])
j=next1[j];
if(b[i]==b[j+1])j++;
next1[i]=j;
}
}
//b串匹配a串:如果到不匹配的地方,按next1中求出的可能循环点回溯,没回溯点说明前面不存在可能的相同开头字串,从头开始匹配就好了。
void get_f(){
for(int i=1,j=0;i<=la;i++){
while(j>0&&(a[i]!=b[j+1]))
j=next1[j];//退回操作:找j之前中可能的一个节点;
if(a[i]==b[j+1])
j++;
st[++top]=i;
f[i]=j;
if(j==lb){
top-=lb;
j=f[st[top]];
}
}
}
signed main(){
scanf("%s%s",a+1,b+1);
la=strlen(a+1);lb=strlen(b+1);
KMP();get_f();
for(int i=1;i<=top;i++) printf("%c",a[st[i]]);
return 0;
}
手写栈,tql