LeetCode208. 實現 Trie (字首樹)
阿新 • • 發佈:2020-08-13
方法一
可以直接用一個數組trie存放所有插入的字串,然後insert和startsWith操作只需要遍歷trie陣列,逐個判斷即可。
程式碼:
class Trie { public: vector<string> trie; /** Initialize your data structure here. */ Trie() { } /** Inserts a word into the trie. */ void insert(string word) { trie.push_back(word); } /** Returns if the word is in the trie. */ bool search(string word) { for(const auto &s : trie) { if(s == word) { return true; } } return false; } /** Returns if there is any word in the trie that starts with the given prefix. */ bool startsWith(string prefix) { int size = prefix.size(); for(const auto &s : trie) { if(s.size() >= size && s.substr(0, size) == prefix) { return true; } } return false; } }; /** * Your Trie object will be instantiated and called as such: * Trie* obj = new Trie(); * obj->insert(word); * bool param_2 = obj->search(word); * bool param_3 = obj->startsWith(prefix); */
方法二
方法一併不是嚴格的trie樹。
我們可以用一個結構體存放trie樹的每個節點,每個節點最多可能有a~z共26個孩子,為了方便,我們都用整數表示;另外每個節點還需要記錄它們是否是一個單詞的結尾,
可以用一個布林變數is_end表示。
插入的時候,從根節點(空)開始,看當前節點對應的孩子是否和現在這個字母匹配,如果匹配,就繼續往下走,如果不匹配,就插入一個字母,實際上,這就是trie樹。
搜尋的時候同理,如果當前節點對應的孩子和現在查詢的字母相同,就繼續往下走,否則返回false,如果最後存在一條路徑,從根節點到某個節點上的字母組合成了查詢的字串,
還需要看看結尾的字母的is_end變數是否為true,只有當路徑存在且路徑最後一個字母的is_end變數為true時表示搜尋成功。
startsWith和搜尋類似,只不過我們只需要找到路徑即可,即使路徑最後一個節點的is_end變數不為true也沒關係,只要存在路徑,就說明有單詞是以字串prefix開頭的,返回true。
class Trie { public: struct Node { Node* son[26]; //節點最多有26個孩子 bool is_end; //如果節點是某個單詞的結尾,標記一下 }*root; /** Initialize your data structure here. */ Trie() { root = new Node(); } /** Inserts a word into the trie. */ void insert(string word) { Node* p = root; //p表示我們當前是在哪個節點,最開始在根節點(空) for(int i = 0; i < word.size(); ++i) { //從根節點開始逐層往下搜尋 int u = word[i] - 'a'; if(p -> son[u] == NULL) { //如果某節點不存在,則新建一個節點 p -> son[u] = new Node(); } p = p -> son[u]; //繼續往下走 } p -> is_end = true; //標記一下這是一個單詞的結尾 } /** Returns if the word is in the trie. */ bool search(string word) { Node* p = root; for(int i = 0; i < word.size(); ++i) { int u = word[i] - 'a'; if(p -> son[u] == NULL) { return false; //如果沒找到,返回false } p = p -> son[u]; } return p -> is_end; //找到一條路徑上的單詞和word相同,還要看一下is_end變數是否為true,因為這可能是某個單詞的字首 } /** Returns if there is any word in the trie that starts with the given prefix. */ bool startsWith(string prefix) { //startsWith和search類似,唯一不同就是隻要路徑存在就返回true Node* p = root; for(int i = 0; i < prefix.size(); ++i) { int u = prefix[i] - 'a'; if(p -> son[u] == NULL) { return false; } p = p -> son[u]; } return true; } }; /** * Your Trie object will be instantiated and called as such: * Trie* obj = new Trie(); * obj->insert(word); * bool param_2 = obj->search(word); * bool param_3 = obj->startsWith(prefix); */