1. 程式人生 > >CH601字尾陣列【Trie樹】

CH601字尾陣列【Trie樹】

內含字典樹建立及查詢模板

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\n", searchh(s)); 55 } 56 return 0; 57 }