目录
hiho 218 Keywords Filter
题目1 : Keywords Filter
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
You are given a string S which consists of only lower case letters and N keyword W1, W2, … WN which also consists of only lower case letters. For each appearance of a keyword in S you need to change the letters matching the keyword into ‘*’.
Assume S = “abcxyzabcd” and keywords are {“abc”, “cd”}, the filtered S’ will be “***xyz****”.
输入
The first line contains an integer N. (1 <= N <= 1000)
The following N lines each contains a keyword. The total length of the keywords is no more than 100000.
The last line contains the string S. The length of S is no more than 100000.
输出
The filtered string.
样例输入
2
abc
cd
abcxyzabcd
样例输出
***xyz****
题意分析:
1.题是什么?
给你1000个长度为100000以内的屏蔽词,然后给你一段长度100000以内的文章,要把文章中所有屏蔽词都换成’*’号然后输出.
2.思路
(1)ac自动机?单纯kmp?
字符串多模匹配,妥妥的ac自动机模版题的感觉啊,不过我个人有点没搞懂ac自动机的fail指针那个地方而且很久没写ac自动机了,故而ac自动机的解法后面会补上,下面放我只用kmp配合一些优化成功ac的解法:
首先不知道kmp是什么算法的可以看我另一篇博客 kmp详解
(2)单纯kmp时间空间复杂度分析
首先分析解法的时间复杂度,我们知道kmp时间复杂度是m+n的,故而如果单纯的用kmp,预计时间复杂度会是在1000*(100000+100000),也就是2亿,时间上勉强能接受,空间复杂度上需要先存下那1000个关键字,最极限需要1亿个char空间,空间上很悬然而我这样存没出事,看来输入是手下留情了的.
(3)解法以及关键优化
解法是以对每个屏蔽词以kmp做匹配,匹配成功则屏蔽相应段,然而单纯这么做只能过90%数据,因为这么做存在时间复杂度暴涨的特例:
对于文章aaaaaaaaaaaaaaaaaaaaaa,屏蔽词aaaaaa在文章中做kmp会多次匹配成功,每次都傻傻的屏蔽相应段会造成时间复杂度暴涨为(m-n)*n,几乎是m*n,故而我们需要做一下优化:
导致时间复杂度暴涨的关键是我们重复屏蔽了某些段,故而我们只要做一个lastpingbi存最后屏蔽的地方,循环时以lastpingbi为辅助边界,就可以避免重复屏蔽,成功ac
(4)ac自动机做法
待补充
ac代码
1.单纯kmp
#include <iostream>
using namespace std;
const int maxn=100005;
string keyword[1000];
int ntext[maxn];//ntext数组
void getntext(string s){//构造ntext数组,真正的模版
ntext[0]=-1;
int i=0,j=-1; //j为什么初值赋值-1?0其实也行,仅仅是为了少一个判断,
while(s[i]){
if(j==-1||s[i]==s[j]) ntext[++i]=++j;
else j=ntext[j];
}
}
int lastpingbi; //这个非常重要,没有这个只能过90%数据
string wordsfilter(string a,string b,string ans){
lastpingbi=0;
int blen=0;
while(b[blen]) blen++;
getntext(b);
int i=0,j=0;
while(a[i]){
if(j==-1||a[i]==b[j]){
i++,j++;
if(!b[j]){
for(int l=i-1;l>=std::max(lastpingbi,i-blen);l--) ans[l]='*';
lastpingbi=i-1;
j=ntext[j];
}
}
else j=ntext[j];
}
return ans;
}
void solve(){
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>keyword[i];
string str,ans;
cin>>str;
ans=str;
for(int i=0;i<n;i++) ans=wordsfilter(str,keyword[i],ans);
cout<<ans<<endl;
}
int main(){
solve();
return 0;
}