LeetCode 208. Implement Trie (Prefix Tree) 实现 Trie (前缀树)(C++/Java)
题目:
Implement a trie with insert
, search
, and startsWith
methods.
Example:
Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // returns true trie.search("app"); // returns false trie.startsWith("app"); // returns true trie.insert("app"); trie.search("app"); // returns true
Note:
- You may assume that all inputs are consist of lowercase letters
a-z
. - All inputs are guaranteed to be non-empty strings.
分析:
实现一个前缀树,包含insert
, search
, and startsWith三个方法,分别对应插入,搜索单词和搜索前缀三个方法。
前缀树在这里就不多说了,网上的介绍有很多。
下面说一下具体的实现。
因为只有a-z共26个英文字母,所有开辟一个26大小的数组用来保存节点,isEnd用来表示该节点是否为单词终止节点,例如apple,那么在e节点时应该将isEnd置为true,以便搜索方法查询单词。
Trie* node[26] = {nullptr}; bool isEnd = false;
insert插入一个单词,遍历单词的每一个字符,从根节点开始查询对应位置的数组是否为空,如果为空就在对应位置新建节点,然后继续,在最后一个字符对应的位置isEnd记为true
void insert(string word) { Trie* p = this; for(const char ch:word){ if(p->node[ch-'a'] == nullptr) p->node[ch-'a'] = new Trie(); p = p->node[ch-'a']; } p->isEnd = true; }
search
, and startsWith可以通过一个辅助函数来实现,遍历单词的字符,如果对应位置为null则表示前缀树中没有这个字符,返回null即可,否自返回查询到的最后一个结点。通过结点来判断单词是否存在,如果isEnd为true则search返回true。
Trie* mySearch(string word){ Trie *p = this; for (auto c : word){ if (p->node[c - 'a'] == nullptr) return nullptr; p = p->node[c - 'a']; } return p; }
程序:
C++
class Trie { public: /** Initialize your data structure here. */ Trie() { //root = new Trie(); } /** Inserts a word into the trie. */ void insert(string word) { Trie* p = this; for(const char ch:word){ if(p->node[ch-'a'] == nullptr) p->node[ch-'a'] = new Trie(); p = p->node[ch-'a']; } p->isEnd = true; } /** Returns if the word is in the trie. */ bool search(string word) { Trie* res = mySearch(word); return res && res->isEnd; } /** Returns if there is any word in the trie that starts with the given prefix. */ bool startsWith(string prefix) { return mySearch(prefix) != nullptr; } private: //Trie* root; Trie* node[26] = {nullptr}; bool isEnd = false; Trie* mySearch(string word){ Trie *p = this; for (auto c : word){ if (p->node[c - 'a'] == nullptr) return nullptr; p = p->node[c - 'a']; } return p; } };
Java
class Trie { /** Initialize your data structure here. */ public Trie() { } /** Inserts a word into the trie. */ public void insert(String word) { Trie p = this; char[] w = word.toCharArray(); for(char ch:w){ if(p.node[ch - 'a'] == null) p.node[ch - 'a'] = new Trie(); p = p.node[ch - 'a']; } p.isEnd = true; } /** Returns if the word is in the trie. */ public boolean search(String word) { Trie res = find(word); return res != null && res.isEnd; } /** Returns if there is any word in the trie that starts with the given prefix. */ public boolean startsWith(String prefix) { return find(prefix) != null; } private Trie[] node = new Trie[26]; private boolean isEnd = false; private Trie find(String word){ Trie p = this; char[] w = word.toCharArray(); for(char ch:w){ if(p.node[ch - 'a'] == null) return null; p = p.node[ch - 'a']; } return p; } } /** * Your Trie object will be instantiated and called as such: * Trie obj = new Trie(); * obj.insert(word); * boolean param_2 = obj.search(word); * boolean param_3 = obj.startsWith(prefix); */