字典樹 : 見名知意(在樹上進行查詢)。 跟字典相關的一定與查詢有密切的關係, 查詢就須要必定的媒介做爲支撐,樹就爲這種查詢提供支撐。
實現字符串快速檢索的多叉樹結構。 常見的字符串轉化:小寫字母或者大寫字母組成的字符串,數字組成的字符串,01編碼組成的字符串。
Trie 的每一個節點都擁有若干個字符指針,就是說每一個節點有多個子節點,通俗一點就是至關於古代 的大少爺能夠有多個妻子。
一、插入(將一個字符串插入到字典樹上) 二、檢索(檢索一個字符串 S 在Trie 上是否存在)
假設有單詞 : cab , cef , da 這樣三個單詞,那麼這樣三個單詞組成的圖是什麼樣的呢 ? 看下圖 : (一般還要在末尾進行標記一下,表示到字符串的末尾)
插入 : 像每一個單詞拼寫同樣,單詞的開頭就至關因而咱們的根,從根節點出發,向兒子節點前進。 在向下走的過程當中,看有沒有當前這個字符的節點,若是有這個節點,就順着這個節點繼續 往下走,若是沒有這個節點,就在這個節點之下再建立一個節點。 拿一個例子來講: 好比上圖的 cab 和 cef, 先插入第一個字符串,從根節點出發,第一個字符是 c,咱們發 現沒有這個字符的節點,因此建立一個節點,將指針節點進行指向,而後一直向下移動,知道 字符串結尾。再插入第二個字符串,先檢測第一個字符是否存在,咱們發現存在,因此不用 建立,直接向下移動指針節點便可。 能夠發現: 一個節點最多能夠有26個孩子。 檢索: 只須要將字符串遍歷一遍,順着根節點下來看這條路徑上是否有不存在的值,即 0,若是 沒有到末尾就發現有 0 ,說明這個字符串不存在,反之即存在。
插入:ios
void insert(char str[]) { int len = strlen(str),p = 0; // p 做爲根節點從 0 開始 for(int i = 0; i < len; i ++) { int ch = str[i] - 'a'; if(trie[p][ch] == 0) trie[p][ch] = ++ idx; // 建立新的節點 p = trie[p][ch]; // 指針移動 } End[p] = true; // 在末尾進行標記 return ; }
檢索:數組
bool query(char str[]) { int len = strlen(str),p = 0; for(int i = 0; i < len; i ++ ){ int ch = str[i] - '0'; if(trie[p][ch] != 0) { p = trie[p][ch]; } else { break; // 及時跳出 } } return true; }
題目連接: https://www.acwing.com/problem/content/144/ 題目描述:給定N個字符串S1,S2…SN,接下來進行M次詢問,每次詢問給定一個字符串T,求S1~SN中有多少個字符串是T的前綴。 輸入字符串的總長度不超過106,僅包含小寫字母。 輸入格式 第一行輸入兩個整數N,M。 接下來N行每行輸入一個字符串Si。 接下來M行每行一個字符串T用以詢問。 輸出格式 對於每一個詢問,輸出一個整數表示答案。 每一個答案佔一行。 輸入樣例: 3 2 ab bc abc abc efg 輸出樣例: 2 0
析題得說: 統計每一個字符串出現的個數便可,用一個cnt[]數組記錄每一個字符串出現的個數,而後進行檢索要處理的字符串,累加結果(模板題)編碼
#include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int SIZE = 1e6 + 10; int trie[SIZE][26],cnt[SIZE]; char str[SIZE]; int n,m,idx = 0; int main(void) { void insert(); int query(); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i ++) { scanf("%s",str); insert(); } while(m --) { scanf("%s",str); printf("%d\n",query()); } return 0; } void insert() { int p = 0; for(int i = 0; i < strlen(str); i ++) { int ch = str[i] - 'a'; if(trie[p][ch] == 0) trie[p][ch] = ++ idx; p = trie[p][ch]; } cnt[p] ++; // 統計該字符串的個數 return ; } int query() { int p = 0,res = 0; for(int i = 0 ; i < strlen(str); i ++) { int ch = str[i] - 'a'; if(trie[p][ch] != 0) { p = trie[p][ch]; res += cnt[p]; // 將以該字符結尾的數量累加,最後結果就是前綴字符串的數量 } else { break; } } return res; }