记录一下每个节点之后26个字母首次出现的位置,搜索的时候只需要枚举起点就行了。
RE了两天,原因居然是字符串结尾的时候没加'\0',坑爹,这种错误编译器应该给报出来嘛。
具体信息看代码,很详细,为了找bug,我把思路理了好多遍。。。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n[12000][26];
char s[12000];
char ch[120];
void insert(char * ch)
{
int len1=strlen(ch); //带插入字符串的长度
int len=strlen(s); //现有字符串的长度
for (int i=0;i<len1;i++) //对每个带插入的字符
{
int id=ch[i]-'a'; //获取其id
for (int t=len-1;t>=0;t--) //对于已经处理好的串,从末尾向前扫描
{
n[t][id]=len; //将现有串的下一个id出现的位置设为带插入字符的位置
if (s[t]==ch[i]) //如果发现了当前字符,证明再往前不需更新,跳出
break;
}
s[len]=ch[i]; //插入字符
len++; //现有字符串的长度++
}
s[len]='\0';
}
bool find(char * ch)
{
int x=ch[0]-'a'; //获取查找串的首字符
int len=strlen(s); //模板串长度
int len1=strlen(ch); //查找串长度
int cur=0; //设当前位置为模板串的第一个位置
if (s[cur]!=ch[0]) //如果模板串的第一个位置和查找串首字符不同,设为首字符首次出现的位置
cur=n[cur][x];
while (cur!=-1) //如果首字符出现的位置不为-1,即可以出现
{
int next=cur; //next临时变量,执行查找操作
int p=0;
int i;
for (i=1;i<len1;i++) //依次查找下一个字符
{
int id=ch[i]-'a'; //下一个字符的id
next=n[next][id]; //next=当前位置下一个id字符出现的位置
if (next==-1) //如果为-1,证明当前位置之后没有
{
next=0; //由于串可以左移,即可以向后构成环,故从头开始查找
if (s[next]!=ch[i]) //如果当前位置不等于待查找位置字符,则设为下一个字符出现的位置
next=n[next][id];
if (next==-1) //如果下一个字符出现的位置为-1,说明串中无这个字符,跳出循环
break;
p++; //否则循环的次数+1
}
if (p>1) //循环超过一次,不符合
break;
if (p==1&&next>=cur) //循环一次但是当前位置在cur的右边或者在cur,不符合
break;
}
if (i==len1) //如果查找到了最后一个字符,则证明能查找到
return true;
cur=n[cur][x]; //否则看下一个起点
}
return false;
}
int main()
{
int T;
cin>>T;
while (T--)
{
memset(n,-1,sizeof(n));
scanf("%s",s);
int len=strlen(s);
for (int i=0;i<len;i++) //对于n数组,初始化工作
{
for (int t=i+1;t<len;t++) //对当前字符之后的位置
{
int id=s[t]-'a'; //获取id
if (n[i][id]==-1) //如果当前字符这个id为0,设为t
n[i][id]=t;
}
}
int m;
scanf("%d",&m);
int p;
while (m--)
{
scanf("%d",&p);
scanf("%s",ch);
if (p==1)
insert(ch);
else
{
if (find(ch))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
}
}