P4824 [USACO15FEB] Censoring S (栈模拟,KMP)

题意:

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值