//KMP模板1,简单的字符串匹配
void GetNextVal(int* p) //得next数组;next[i]是下标为i的字符之前后缀和前缀相同的最长长度 { next[0]=-1; int k=-1,j=0; while(j<m-1) { if(k==-1||p[j]==p[k]) { if(p[++j]==p[++k]) //当两个字符相等时要跳过(优化) next[j]=next[k]; else next[j]=k; } else { k=next[k]; } } } int KmpSearch(int* s,int* p) //在主串中查找子串出现的位置 { int i=0,j=0; //i是主串的位置,j是模式串的位置 while(i<n&&j<m) { if(j==-1||s[i]==p[j]) // j为-1,主串后移一位;当两个字符相同,就比较下一个 { ++i; ++j; } else { j=next[j]; //只移动模式串,回到指定位置 } } if(j==m) return i-j; //如果找到,返回在主串中第一个字符出现的下标,否则为-1 else return -1; }
//KMP模板2,求模式串在待匹配串中的出现次数(不重复) void GetNextVal(char* p) { next[0]=-1; int k=-1,j=0; while(j<m-1)//m为模式串长度 { if(k==-1||p[j]==p[k]) { if(p[++j]==p[++k]) next[j]=next[k]; else next[j]=k; } else { k=next[k]; } } } int KmpSearch(char* s,char* p) { int i=0,j=0,cnt=0; while(i<n)//n为主串长度 { if(j==-1||s[i]==p[j]) { ++i; ++j; } else { j=next[j]; } if(j==m)//m为模式串长度 { cnt++; j=0;//找到之后模式串回到最开头位置 } } return cnt;//返回出现次数 }
//KMP模板3,求模式串在待匹配串中的出现次数(可重复) void GetNextVal(char* p) { next[0]=-1; int k=-1,j=0; while(j<m) //m为模式串长度 { if(k==-1||p[j]==p[k]) //这里不要优化 { next[++j]=++k; } else { k=next[k]; } } } int KmpSearch(char* s,char* p) { int i=0,j=0,cnt=0; while(i<n)//n为主串长度 { if(j==-1||s[i]==p[j]) { ++i; ++j; } else { j=next[j]; } if(j==m)//m为模式串长度 { cnt++; j=next[j];//找到之后模式串回到指定位置 } } return cnt;//返回出现次数 }
//字典树模板(插入和查找) void insert()//插入单词s { len=strlen(s);//单词s的长度 root=0;//根节点编号为0 for(int i=0;i<len;i++) { int id=s[i]-'a';//第二种编号 if(!trie[root][id])//如果之前没有从root到id的前缀 trie[root][id]=++tot;//插入,tot即为第一种编号 root=trie[root][id];//顺着字典树往下走 } } bool find() //查找单词s { len=strlen(s); root=0;//从根结点开始找 for(int i=0;s[i];i++) { int x=s[i]-'a';// if(trie[root][x]==0) return false;//以root为头结点的x字母不存在,返回0 root=trie[root][x];//为查询下个字母做准备,往下走 } return true;//找到了 }
//字典树完整模板1,查询是否出现(前缀或整个单词) /* trie tree的储存方式:将字母储存在边上,边的节点连接与它相连的字母 trie[rt][x]=tot:rt是上个节点编号,x是字母,tot是下个节点编号 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define maxn 2000010 using namespace std; int tot=1,n; int trie[maxn][26]; //bool isw[maxn];查询整个单词用 void insert(char *s,int rt) { for(int i=0;s[i];i++) { int x=s[i]-'a'; if(trie[rt][x]==0)//现在插入的字母在之前同一节点处未出现过 { trie[rt][x]=++tot;//字母插入一个新的位置,否则不做处理 } rt=trie[rt][x];//为下个字母的插入做准备 } /*isw[rt]=true;标志该单词末位字母的尾结点,在查询整个单词时用到*/ } bool find(char *s,int rt) { for(int i=0;s[i];i++) { int x=s[i]-'a'; if(trie[rt][x]==0)return false;//以rt为头结点的x字母不存在,返回0 rt=trie[rt][x];//为查询下个字母做准备 } return true; //查询整个单词时,应该return isw[rt] } char s[22]; int main() { tot=0; int rt=1; scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>s; insert(s,rt); } scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>s; if(find(s,rt))printf("YES\n"); else printf("NO\n"); } return 0; }
//字典树完整模板2,查询前缀出现次数 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; int trie[400001][26],len,root,tot,sum[400001]; bool p; int n,m; char s[11]; void insert() { len=strlen(s); root=0; for(int i=0;i<len;i++) { int id=s[i]-'a'; if(!trie[root][id]) trie[root][id]=++tot; sum[trie[root][id]]++;//前缀后移一个位置保存 root=trie[root][id]; } } int search() { root=0; len=strlen(s); for(int i=0;i<len;i++) { int id=s[i]-'a'; if(!trie[root][id]) return 0; root=trie[root][id]; }//root经过此循环后变成前缀最后一个字母所在位置的后一个位置 return sum[root];//因为前缀后移了一个保存,所以此时的sum[root]就是要求的前缀出现的次数 } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>s; insert(); } scanf("%d",&m); for(int i=1;i<=m;i++) { cin>>s; printf("%d\n",search()); } }
//字典树模板指针写法 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; char s[11]; int n,m; bool p; struct node { int count; node * next[26]; }*root; node * build() { node * k=new(node); k->count=0; memset(k->next,0,sizeof(k->next)); return k; } void insert() { node * r=root; char * word=s; while(*word) { int id=*word-'a'; if(r->next[id]==NULL) r->next[id]=build(); r=r->next[id]; r->count++; word++; } } int search() { node * r=root; char * word=s; while(*word) { int id=*word-'a'; r=r->next[id]; if(r==NULL) return 0; word++; } return r->count; } int main() { root=build(); scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>s; insert(); } scanf("%d",&m); for(int i=1;i<=m;i++) { cin>>s; printf("%d\n",search()); } }
//manacher模板,求字符串中最长回文串长度 const int maxn=1000010; char MA[maxn<<1]; int MP[maxn<<1]; void Manacher(char s[],int len) { int l=0; MA[l++]='$'; MA[l++]='#'; for(int i=0;i<len;i++) { MA[l++]=s[i]; MA[l++]='#'; } MA[l]=0; int mx=0,id=0; for(int i=0;i<l;i++) { MP[i]=mx>i?min(MP[2*id-i],mx-i):1; while(MA[i+MP[i]]==MA[i-MP[i]]) MP[i]++; if(i+MP[i]>mx) { mx=i+MP[i]; id=i; } } } char s[maxn]; int main() { while(scanf("%s",s)!=EOF) { int len=strlen(s); Manacher(s,len); int ans=0; for(int i=0;i<2*len+2;i++) ans=max(ans,MP[i]-1); printf("%d\n",ans); } return 0; }