【题解】「USACO2015FEB」Censoring (Silver银组)(KMP)

题面

【题目描述】
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;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值