學習影片:Bilibili左程云【算法讲解044【必备】前缀树原理和代码详解】
學習影片:Bilibili左程云【算法讲解045【必备】前缀树的相关题目】
概述
字典樹是一個類似於hash table的樹結構,但有著更方便的查找功能,也可以
- 查詢特定字串的出現次數
- 查詢以某某字串為開頭的次數
方法概要與原理
我們依次輸入,每個字串都從根節點(頭節點, root)開始,依序將每一個字串插入到 樹 結構中,找到就往該節點走,找不到就新增,每一個節點:
- 代表一個特定字元(char),依照字串順序插入
- 有一個int passed,代表該節點被passed多少次,只要節點被經過就+1
- 有一個int stop,代表有幾個字串stop在這個節點,字串以該節點做 結尾就+1
- 優點
- 方便查找任意形式的字串
- 查詢速度快 O(strlen)
- 缺點
基礎版code
- void init() 初始化
- void insert(string word) 將字串插入樹中
- int search(string word) 回傳符合 word 的個數 (也就是看passed)
- int prefixNumber(string prefix) 回傳前綴為 prefix 的個數 (也就是看stop)
- void erase(string word) 將 word 從樹中移除
使用靜態陣列實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| int tree[MAXN][size] = {}; int passed[MAXN] = {}; int stop[MAXN] = {};
int cnt = 1;
void init(){ for(int i=1; i<=cnt; ++i){ for(int j=0; j<size; ++j) tree[i][j] = 0; passed[i] = 0; stop[i] = 0; } cnt = 1; }
void insert(string word){ int curr = 1; ++passed[curr]; for(int i=0, path; i<word.length(); ++i){ path = word.at(i) - 'a'; if(tree[curr][path] == 0) tree[curr][path] = ++cnt; curr = tree[curr][path]; ++passed[curr]; } ++stop[curr]; }
int search(string word){ int curr = 1; for(int i=0, path; i<word.length(); ++i){ path = word.at(i) - 'a'; if(tree[curr][path] == 0) return 0; curr = tree[curr][path]; } return stop[curr]; }
int prefixNumber(string word){ int curr = 1; for(int i=0, path; i<word.length(); ++i){ path = word.at(i) - 'a'; if(tree[curr][path] == 0) return 0; curr = tree[curr][path]; } return passed[curr]; }
void erase(string word){ if(search(word) == 0) return; int curr = 1; --passed[curr]; for(int i=0, path; i<word.length(); ++i){ path = word.at(i) - 'a'; if(--passed[tree[curr][path]] == 0){ tree[curr][path] = 0; return; } curr = tree[curr][path]; } --stop[curr]; }
|
練習題目與題解
牛客NowCoder 字典树的实现
牛客NowCoder 接头密匙
LeetCode Maximum XOR of Two Numbers in an Array
LeetCode Word Search II