内含字典树创建及查询模板
1601 前缀统计 0x10「基本数据结构」例题
描述
给定N个字符串S1,S2...SN,接下来进行M次询问,每次询问给定一个字符串T,求S1~SN中有多少个字符串是T的前缀。输入字符串的总长度不超过10^6,仅包含小写字母。
输入格式
第一行两个整数N,M。接下来N行每行一个字符串Si。接下来M行每行一个字符串表示询问。
输出格式
对于每个询问,输出一个整数表示答案
样例输入
3 2 ab bc abc abc efg
样例输出
2 0
思路:
用scanf !=EOF最后一组不知道为什么就是会RE
虐狗宝典字典树笔记:
Trie树,字典树每个节点拥有若干个字符指针,在插入或检索字符串时扫到一个字符c就沿着当前节点的c字符指针走下去。
初始时,空Trie仅包含一个根节点,字符指针均为空。
插入S时,我们令一个指针p指向根节点,依次扫描S中的每一个字符c。
1.若p的c字符指针指向一个已经存在的节点Q,则令P=Q
2.若p的c字符指针指向空,则新建一个节点Q,令p的c字符指针指向Q,然后令P=Q
当S扫描完毕,当前节点P上标记他是一个字符串的末尾
检索S是否在Trie中存在,令一个指针P指向根节点,依次扫描S中的每个字符c
1.若P的c字符指针指向空,则说明S没有被插入过Trie,结束检索
2.若P的c字符指针指向一个已经存在的节点Q,则令P=Q
当S中的字符扫描完毕,若当前节点P被标记为一个字符串的末尾,说明S在Trie中存在。
本题与讲解的不同之处在于末尾应标记出现的次数,检索时也应该同时统计所经过节点的作为末尾的次数。
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <map> 8 using namespace std; 9 typedef long long LL; 10 #define inf 0x7f7f7f7f 11 12 int n, m; 13 const int maxn = 1e6 + 10; 14 int trie[maxn][26], tot = 1, ed[maxn]; 15 char s[maxn]; 16 17 void insertt(char *str) 18 { 19 int len = strlen(str), p = 1; 20 for(int k = 0; k < len; k++){ 21 int ch = str[k] - 'a'; 22 if(trie[p][ch] == 0){ 23 trie[p][ch] = ++tot; 24 } 25 p = trie[p][ch]; 26 } 27 ed[p]++; 28 } 29 30 int searchh(char* str) 31 { 32 int ans = 0; 33 int len = strlen(str), p = 1; 34 for(int k = 0; k < len; k++){ 35 36 p = trie[p][str[k] - 'a']; 37 if(p == 0)return ans; 38 ans += ed[p]; 39 } 40 //ans += ed[p]; 41 return ans; 42 } 43 44 int main() 45 { 46 scanf("%d%d", &n, &m); 47 48 for(int i = 1; i <= n; i++){ 49 scanf("%s", s); 50 insertt(s); 51 } 52 for(int j = 1; j <= m; j++){ 53 scanf("%s", s); 54 printf("%d ", searchh(s)); 55 } 56 return 0; 57 }