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!='
')
	{
		c=getchar();
		if(c=='
')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