由于模式串不一定是以前缀出现,所以普通的字典树插入是不行的。可以考虑将母串的每一个后缀串都插入一遍,就可以达到查询时遍历母串的所有位置为起点,而不是仅仅以前缀的遍历方式。此外还要考虑到诸如样例中的用d去匹配add,按上述方式会产生重复,所以可以考虑在Trie结构中加入id编号,只有在不是同一个id时再进行计数。详情看代码。
#include <iostream> #include <stdio.h> #include <algorithm> #include <cmath> #include <string> #include <string.h> #include <set> #include <cstring> using namespace std; const int maxt = 10004; //char str[maxt]; typedef struct Trie_node { int count; // 统计单词前缀出现的次数 struct Trie_node* next[26]; // 指向各个子树的指针 bool exist; // 标记该结点处是否构成单词 int id; //标记当前串的编号 }TrieNode , *Trie; TrieNode* createTrieNode() { TrieNode* node = (TrieNode *)malloc(sizeof(TrieNode)); node->count = 0; node->id=-1; //记得root不包含任何字符,所以要进行区分 node->exist = false; memset(node->next , 0 , sizeof(node->next)); return node; } void Trie_insert(Trie root, char* word,int iid) { Trie node = root; char *p = word; int id; while( *p ) { id = *p - 'a'; if(node->next[id] == NULL) { node->next[id] = createTrieNode(); } node = node->next[id]; ++p; if(node->id!=iid) node->count += 1,node->id=iid; //修改id的时候也应该在判断是否是同一个串里的子串后 } node->exist = true; } int Trie_search(Trie root, char* word) { Trie node = root; char *p = word; int id; while( *p ) { id = *p - 'a'; node = node->next[id]; ++p; if(node == NULL) return 0; } return node->count; } 静态字典树模板 void de(Trie p) { if(p==NULL) return ; int i; for(i=0;i<10;i++) { de(p->next[i]); } free(p); } int main() { int t; scanf("%d",&t); Trie root=createTrieNode(); char str[22]; for(int i=1;i<=t;i++){ scanf("%s",str); int len=strlen(str); for(int j=0;j<len;j++){ Trie_insert(root,str+j,i); } } int q; scanf("%d",&q); int ans=0; for(int i=0;i<q;i++){ scanf("%s",str); printf("%d\n",Trie_search(root,str)); } //printf("%d\n",ans); return 0; }