算法基礎——Trie字符串統計

原題連接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;
}
相關文章
相關標籤/搜索