1. 程式人生 > 其它 >Trie字首樹

Trie字首樹

轉載自:https://leetcode-cn.com/problems/implement-trie-prefix-tree/原題

Trie(發音類似 "try")或者說 字首樹 是一種樹形資料結構,用於高效地儲存和檢索字串資料集中的鍵。這一資料結構有相當多的應用情景,例如自動補完和拼寫檢查。

插入字串

我們從字典樹的根開始,插入字串。對於當前字元對應的子節點,有兩種情況:

  • 子節點存在。沿著指標移動到子節點,繼續處理下一個字元。
  • 子節點不存在。建立一個新的子節點,記錄在children 陣列的對應位置上,然後沿著指標移動到子節點,繼續搜尋下一個字元。

重複以上步驟,直到處理字串的最後一個字元,然後將當前節點標記為字串的結尾。

查詢字首

我們從字典樹的根開始,查詢字首。對於當前字元對應的子節點,有兩種情況:

  • 子節點存在。沿著指標移動到子節點,繼續搜尋下一個字元。
  • 子節點不存在。說明字典樹中不包含該字首,返回空指標。

重複以上步驟,直到返回空指標或搜尋完字首的最後一個字元。

若搜尋到了字首的末尾,就說明字典樹中存在該字首。此外,若字首末尾對應節點的isEnd為真,說明Trie中存在該string

程式碼

 1 class Trie {
 2 private:
 3     vector<Trie*> children;
 4     bool isEnd;
 5 
 6     Trie* searchPrefix(string
prefix) { 7 Trie* node = this; 8 for (char ch : prefix) { 9 ch -= 'a'; 10 if (node->children[ch] == nullptr) { 11 return nullptr; 12 } 13 node = node->children[ch]; 14 } 15 return node; 16 }
17 18 public: 19 Trie() : children(26), isEnd(false) {} 20 21 void insert(string word) { 22 Trie* node = this; 23 for (char ch : word) { 24 ch -= 'a'; 25 if (node->children[ch] == nullptr) { 26 node->children[ch] = new Trie(); 27 } 28 node = node->children[ch]; 29 } 30 node->isEnd = true; 31 } 32 33 bool search(string word) { 34 Trie* node = this->searchPrefix(word); 35 return node != nullptr && node->isEnd; 36 } 37 38 bool startsWith(string prefix) { 39 return this->searchPrefix(prefix) != nullptr; 40 } 41 };

字典樹的應用:

例題:https://leetcode-cn.com/problems/word-search-ii/

給定一個m x n 二維字元網格board和一個單詞(字串)列表 words,找出所有同時在二維網格和字典中出現的單詞。

單詞必須按照字母順序,通過 相鄰的單元格 內的字母構成,其中“相鄰”單元格是那些水平相鄰或垂直相鄰的單元格。同一個單元格內的字母在一個單詞中不允許被重複使用。

輸入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
輸出:["eat","oath"]

實現:

 1 from collections import defaultdict
 2 
 3 
 4 class Trie:
 5     def __init__(self):
 6         self.children = defaultdict(Trie)
 7         self.word = ""
 8 
 9     def insert(self, word):
10         cur = self
11         for c in word:
12             cur = cur.children[c]
13         cur.is_word = True
14         cur.word = word
15 
16 
17 class Solution:
18     def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
19         trie = Trie()
20         for word in words:
21             trie.insert(word)
22 
23         def dfs(now, i1, j1):
24             if board[i1][j1] not in now.children:
25                 return
26 
27             ch = board[i1][j1]
28 
29             now = now.children[ch]
30             if now.word != "":
31                 ans.add(now.word)
32 
33             board[i1][j1] = "#"
34             for i2, j2 in [(i1 + 1, j1), (i1 - 1, j1), (i1, j1 + 1), (i1, j1 - 1)]:
35                 if 0 <= i2 < m and 0 <= j2 < n:
36                     dfs(now, i2, j2)
37             board[i1][j1] = ch
38 
39         ans = set()
40         m, n = len(board), len(board[0])
41 
42         for i in range(m):
43             for j in range(n):
44                 dfs(trie, i, j)
45 
46         return list(ans)