structTrie { int num; Trie* next[26]; Trie() { for (int i = 0; i <= 25; i++) next[i] = NULL; num = 0; } };
Trie *root = new Trie;
voidInsert(char* word){ Trie* p = root; for (int i = 0; word[i]; i++) { if (p->next[word[i] - 'a'] == NULL) { p->next[word[i] - 'a'] = new Trie; } p = p->next[word[i] - 'a']; p->num++; } }
voidFreedom(Trie *p){ for (int i = 0; i < 26; i++) { if (p -> next[i] != NULL) Freedom(p -> next[i]); } delete p; }
intFind(char* word){ Trie* p = root; for (int i = 0; word[i]; i++) { if (p->next[word[i] - 'a'] == NULL) { return0; } p = p->next[word[i] - 'a']; } return p->num; }
intmain(){ charword[11]; int n, m; while (cin.getline(word, 12)) { if (strlen(word) == 0) { break; } Insert(word); } while (scanf("%s", word) != EOF) { printf("%d\n", Find(word)); } Freedom(root); return0; }
voidInsert(char *word){ int len = strlen(word); int root = 0; for (int i = 0; i < len; i++) { int id = word[i] - '0'; if (!tree[root][id]) tree[root][id] = ++tot; root = tree[root][id]; flagg[root]++; } //flagg[root] += 1; }
intFind(char* word){ int len = strlen(word); int root = 0; int ans = 0; for (int i = 0; i < len; i++) { int id = word[i] - '0'; if (!tree[root][id]) return0; //if (flagg[tree[root][id]]) //ans += 1; root = tree[root][id]; } ans = flagg[root]; return ans; }
voidinit(){ for (int i = 0; i <= tot; i++) { flagg[i] = false; for (int j = 0; j < 30; j++) { tree[i][j] = 0; } } tot = 0; }
intmain(){ charword[11]; int n, m; init(); while (cin.getline(word, 12)) { if (strlen(word) == 0) { break; } Insert(word); } while (scanf("%s", word) != EOF) { printf("%d\n", Find(word)); } return0; }
//扩展KMP可求问题:给出一个长为N的字符串S,再给出一个长为M的字符串T //求S的所有后缀中和T的最长公共前缀 //假设s为文本串(长度为n),T为模式串(长度为m) char s[N], T[N]; int n, m; int Next[N]; //Next[i]代表T[i~m-1]与T[0~m-1]最长公共前缀 int ex[N]; //extend数组,代表s[i~n-1]与T[0~m-1]最长公共前缀 //注意到,如果有一个位置extend[i]=m,则表示T在S中出现,而且是在位置i出现,这就是标准的KMP问题 voidGet_Next(){ Next[0] = m; int j = 0; while (j + 1 < m && T[j] == T[j + 1]) //计算Next[1] j++; Next[1] = j int po = 1; //设po为答案伸得最远的后缀的下标 for (int i = 2; i < m; i++) int p = Next[po] + po - 1; //已匹配最大位置 int L = Next[i - po]; //前缀长度 if (i + L < p + 1) Next[i] = L; else { j = max(0, p - i + 1); while (i + j < m && T[i + j] == T[j]) j++; Next[i] = j; po = i; } } }
voidEX_KMP(){ Get_Next(); int j = 0; while (j < n && j < m && s[j] == T[j]) j++; ex[0] = j; int po = 0; for (int i = 1; i < n; i++) { int p = ex[po] + po - 1; int L = Next[i - po]; if (i + L < p + 1) ex[i] = L; else { j = max(0, p - i + 1); while (i + j < n && j < m && s[i + j] == T[j]) j++; ex[i] = j; po = i; } } }
四, HASH哈希
单hash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#define base 233 #define inf 1<<30 ull mod = inf; //定义一个大数(最好是质数)作为模数,这里用的是1<<30 //定义一个base进制,这里是233 il ull hash(char s[]){ ll ans = 0; ll len = strlen(s); for(ll i = 0; i < len; i++){ ans = (base * ans + (ull)s[i]) % mod; } return ans; //枚举该字符串的每一位,与base相乘,转化为base进制,加(ull)是为了防止爆栈搞出一个负数,(ull)是无符号的,但其实加了一个ull是可以不用mod的,加个mod更保险 //然而加了mod会很玄学,莫名比不加mod慢了300多ms }