原題連接ios
題目:數組
維護一個字符串集合,支持兩種操做:函數
「I x」向集合中插入一個字符串x;
「Q x」詢問一個字符串在集合中出現了多少次。
共有N個操做,輸入的字符串總長度不超過 10^5,字符串僅包含小寫英文字母。spa
輸入格式code
第一行包含整數N,表示操做數。字符串
接下來N行,每行包含一個操做指令,指令爲」I x」或」Q x」中的一種。get
輸出格式io
對於每一個詢問指令」Q x」,都要輸出一個整數做爲結果,表示x在集合中出現的次數。stream
每一個結果佔一行。變量
數據範圍
1 ≤ N ≤ 2 ∗ 10^4
輸入樣例:
5 I abc Q abc Q ab I ab Q ab
對於代碼中一些變量和數組的分析和說明(見解)
int son[N][26]; son[N][26]這個數組表示的是,一個字符串經過26個字母組成,且長度不會超過N,因此開son數組開成[N][26]。 int cnt[N]; cnt[N]這個數組是用來記錄在一個位置上被打上了多少次標記,該位置上打上的標記次數等於這個字符串出現的字數。 int idx; idx 用來記錄每個字符的所在位置,方便後面詢問(Query)時查找,表示如今最新的可用的下標是多少(和單、雙鏈表中idx的做用相似)。
兩個函數的意義,表達的思想,須要注意的是,咱們是怎麼把Trie樹的理論轉換成代碼實現的
void Insert(char str[]){ int p = 0; /* 0表示根節點,0同時也表示節點爲空(但在p = 0這裏不是表明爲空的意思),每次從根節點開始尋找 */ for(int i = 0; str[i]; i++){ int u = str[i] - 'a'; /* 將字母轉換成數字,方便以後存入Trie樹中 */ if(!son[p][u]) son[p][u] = ++ idx; /* 若是字符串中的某一個字符在Trie樹中不存在,則建立該字符的節點 */ p = son[p][u]; /* 此時的p就是str中最後一個字符對應的trie樹的位置idx。 */ } cnt[p]++; /* 在p這個位置上打上標記,每加一次說明這一個字符串出現了一次 */ } int Query(char str[]){ int p = 0; for (int i = 0; str[i]; i++){ int u = str[i] - 'a'; if (!son[p][u]) return 0; p = son[p][u]; } return cnt[p]; }
完整AC代碼:
#include <iostream> #include <cstdio> using namespace std; const int N = 100010; int son[N][26], cnt[N], idx; void Insert(char str[]){ int p = 0; for(int i = 0; str[i]; i++){ int u = str[i] - 'a'; if(!son[p][u]) son[p][u] = ++ idx; p = son[p][u]; } cnt[p]++; } int Query(char str[]){ int p = 0; for (int i = 0; str[i]; i++){ int u = str[i] - 'a'; if (!son[p][u]) return 0; p = son[p][u]; } return cnt[p]; } int main(){ int n; scanf("%d", &n); char op[2]; while (n--) { char str[N]; scanf("%s%s", op, str); if (op[0] == 'I') Insert(str); else printf("%d\n", Query(str)); } return 0; }