Trie

小码king發表於2024-10-06

835. Trie字串統計

模板題:

維護一個字串集合,支援兩種操作:

  1. I x 向集合中插入一個字串 x;
  2. Q x 詢問一個字串在集合中出現了多少次。

共有 N 個操作,所有輸入的字串總長度不超過 10^5,字串僅包含小寫英文字母。

輸入格式

第一行包含整數 N,表示運算元。

接下來 N 行,每行包含一個操作指令,指令為 I xQ x 中的一種。

輸出格式

對於每個詢問指令 Q x,都要輸出一個整數作為結果,表示 x 在集合中出現的次數。

每個結果佔一行。

資料範圍

1≤N≤2∗10^4

輸入樣例:

5
I abc
Q abc
Q ab
I ab
Q ab

輸出樣例:

1
0
1

個人理解

個人感覺這個Trie是比較簡單理解的,直接給上注意點還有圖解;

AC程式碼:

#include <iostream>
using namespace std;
//定義:不超過 10^5;
//符合要求即可;
const int Ma=100010;
//這裡的26是a~z(字串僅包含小寫英文字母)
//con[Ma]是記錄Trie每個父節點最後一個的子節點(有圖解);
//idx是記錄c的“下標”;
int Trie[Ma][26],con[Ma],idx;   //這裡容易誤解的點:26 a~z並不是層級;而是以a~z帶頭的父節點;
char str[Ma];
//這是構造Trie樹;
void insert(char str[]){
    int p=0;
    for(int i=0;str[i];i++){
        int c=str[i]-'a';
        //如果沒有記錄這個字元,idx開闢一個位置來兜住;
        if(!Trie[p][c]){
            Trie[p][c]=++idx;
        }
        //p來指向下一個;
        p=Trie[p][c];
    }
    //記錄最後一個字元的位置的個數; 比如 abcd 記錄一次,abcd 再來一次 con[p]=2;
    con[p]++;
}
//查詢
int search(char str[]){
    int p=0;
    for(int i=0;str[i];i++){
        int c=str[i]-'a';
        //按順序找下去,不對直接返回0;
        if(!Trie[p][c]){
            return 0;
        }else{
            //指向下一個;
            p=Trie[p][c];
        }
    }
    //返回結果;
    return con[p];
}
int main(){
    int n;
    cin >> n;
    while(n--){
        char c;
        cin >> c >> str;
        if(c=='I'){
           insert(str);
        }else{
            cout << search(str) << endl;
        }
    }
    return 0;
}

圖解:來源--------AC 四谷夕雨

Trie2.PNG

解疑:

Trie[p][c]=++idx; //這是什麼?idx幹什麼用的?    
  • 一維下標:父節點的位置
    二維下標:當前節點的位置(az->025)
    值:當前節點的id(用idx標識,唯一性)
  • 這裡是可以自己圖畫手推的:手推也可能就會發現用這種方法的話,是會浪費一層裡的空間的.......這就自定義想了,在下面我會給出一些例題,是很明顯的吧,有最佳化可以q我
  • 自己手推很重要,本人在沒手推之前,總是覺得字元之間會重複什麼的.......,手推才意識到idx的強大,idx是即將待操作的結點下標 (看自己的理解吧);
  • 哦對,在這以前要知道怎麼構建Trie,要不然夠嗆,比如abcd 的“路徑”是可以儲存 abc的只需記錄最後一個節點;

相關文章