KMP+差分 文章过滤器 (filter)

Description

给定一些短串,要求你在一个长串中,将这些短串部分变为\(*\)

Input

第一行包括一个整数\(n\),表示短串的数量.

接下来的\(n\)行,为\(n\)个短串.

最后一行,为你需要变化的长串.

Output

一行,表示变化后的长串.

PS:长串会有中有各种字符,短串仅包含英文字符

样例输入

3

int

ing

kitty

Int is interesting! ~OwO~

样例输出

\(***\) is \(***\)erest\(***\)ing! ~OwO~

上面的一些输入输出中为全角,实际上为半角.

这题做法有很多啊,可以哈希,可以AC自动机,可以KMP.

这里讲一下KMP算法.

做法为\(KMP+\)差分.

首先需要将长串中的字母全部转为小写(大写).

\(isalpha\)吼啊

我们对每一个短串求出其\(next\)数组.再枚举这些串去和长串匹配.

但是一些位置会出问题.

比如

给定两个短串为\(GRE\)\(eat\),长串为\(Great\)

则我们的长串要变成\(*****\)

因此引入了差分.

如果匹配上之后,我们直接对其左端点和右端点\(+1\)差分。

最终枚举的话,直接判断有无标记,如果有,则将当前位置变为\(*\)

然后直接输出即可.

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#define R register
using namespace std;
char sta[150008],stb[150008];
int pos[150008],k,n,len;
struct cod
{
    int nex[55],len;
    char s[55];
}str[55];
char st[55],c;
inline char ch(char s)
{
    if(!isalpha(s))return s;
    if(s<='Z' and s>='A')s=s-'A'+'a';
    return s;
}
int main()
{
    scanf("%d",&n);
    for(R int i=1;i<=n;i++)
    {
        scanf("%s",st+1);
        str[i].len=strlen(st+1);
        for(R int j=1;j<=str[i].len;j++)
            str[i].s[j]=ch(st[j]);
        str[i].nex[1]=0;k=0;
        for(R int j=2;j<=str[i].len;j++)
        {
            while(str[i].s[k+1]!=str[i].s[j] and k)k=str[i].nex[k];
            if(str[i].s[k+1]==str[i].s[j])k++;
            str[i].nex[j]=k;
        }
    }
    getchar();
    while(c!='\n')
    {
        c=getchar();
        if(c=='\n')break;
        sta[++len]=c;
        stb[len]=ch(c);
    }
    for(R int i=1;i<=n;i++)
    {
        k=0;
        for(R int j=1;j<=len;j++)
        {
            while(k and str[i].s[k+1]!=stb[j])k=str[i].nex[k];
            if(str[i].s[k+1]==stb[j])k++;
            if(k==str[i].len)
            {
                pos[j-str[i].len+1]++;
                pos[j+1]--;
            }
        }
    }
    for(R int i=1;i<=len;i++)
    {
        pos[i]+=pos[i-1];
        if(pos[i])sta[i]='*';
        printf("%c",sta[i]);
    }
}
/*
2
GRE 
eat
Great Britain
***** Britain
*/

转载于:https://www.cnblogs.com/-guz/p/9829149.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值