记模板串为s2,待测串为s1。
对于s2首尾,若没有
,直接一位位匹配直到有
即可。
再考虑s2串为
的情况。其中
是
的某个片度。
我们将
依次从s1的合法位置开始向后匹配。(合法位置初始为0)
用匹配到的第一个位置来更新合法位置。
至于为什么不用s1后面的位置,这是因为用后面的一定不会比用前面的更优。
直到匹配完s2,匹配结束。若任何一步匹配失败,则不是病毒。
注:这种方法不需要限定AGCT。下面的例子也没有限定。
匹配的话用kmp可以做到,但是对于‘?’貌似不好处理。
写的kmp愣是没过。后来打的暴力匹配,没想到比kmp还快......
#include<iostream>
#include<memory.h>
#include<string>
#define maxn 1010
using namespace std;
string s2,s[maxn];
int next1[maxn<<1];
int pipei(string s1,int st,int l,int r){
//在s1的st到lon中查找第一个匹配s2的l到r位的位置hou yi wei
//暴力匹配
for(int i=st;i+r-l<s1.length();i++){
for(int j=l;j<=r;j++){
if(s1[i+j-l]!=s2[j]&&s2[j]!='?')goto End;
if(j==r)return i+j-l+1;
}
End:continue;
}
return -1;
//kmp
/*memset(next1,0,sizeof(next1));
next1[0]=next1[1]=0;int k=0;
for(int i=l+1;i<=r;i++){
while(k&&(s2[k+l]!=s2[i]&&s2[k+l]!='?'))k=next1[k];
next1[i-l+1]=(s2[k+l]==s2[i]||s2[k+l]=='?')?++k:0;
}k=0;
for(int i=st;i<s1.length();i++){
while(k&&s2[k+l]!=s1[i]&&s2[k+l]!='?')k=next1[k];
k+=(s2[k+l]==s1[i]||s2[k+l]=='?');
if(k==r-l+1)return i+1;
}
return -1;*/
}
bool check(string ss){
int shou=0,wei1=ss.length(),wei2=s2.length();
while(s2[shou]!='*'){
if(s2[shou]!=ss[shou]&&s2[shou]!='?')return true;
shou++;
if(shou==wei2)return wei1!=wei2;
if(shou==wei1){
for(int i=shou;i<wei2;i++)
if(s2[i]!='*')return true;
return false;
}
}
while(s2[wei2-1]!='*'){
if(s2[wei2-1]!=ss[wei1-1]&&s2[wei2-1]!='?')return true;
wei1--;wei2--;
if(shou==wei1){
for(int i=shou;i<wei2;i++)
if(s2[i]!='*')return true;
return false;
}
}int st=shou;
//cout<<shou<<' '<<wei1<<' '<<endl<<shou<<' '<<wei2<<endl;
while(1){
if(shou==wei2-1)return false;
for(int i=shou+1;i<wei2;i++)
if(s2[i]=='*'){
if(shou+1==i){
shou++;
continue;
}
st=pipei(ss,st,shou+1,i-1);
if(st==-1)return true;
shou=i;
break;
}
}
}
int main(){
int n,Ans=0;
cin>>s2;cin>>n;
for(int i=1;i<=n;i++){
string ss;cin>>ss;
Ans+=check(ss);
}
cout<<Ans;
return 0;
}
京公网安备 11010502036488号