题目:
Implement a trie with insert
, search
, and startsWith
methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z
.
思路:
前缀树(Prefix Tree,也称Trie)是一种表示英文字典的典型数据结构,它可以最大限度地压缩存储空间,提高查找效率,并且支持前缀查询等。关于前缀树这种数据结构的详细介绍我会在《数据结构》一栏中进行详细介绍,这里仅仅给出一种仅支持26个小写字母的简单前缀树的实现。
1)结点设计:内部成员变量包含一个isTail的布尔值,表示该结点是否是一个单词的最后一个字母;另外包含一组指针列表。因为这道题目中将数据限定为了26个小写字母,所以可以直接用固定大小的指针数组。如果数据的类型和多少不限,则可以将这里的指针数据修改为一个map甚至hash map等,很灵活。
2)前缀树设计:前缀树中只需要包含一个结点类型的成员变量root,表示该前缀树的根节点。所有的操作都将从root开始:
a.insert(string word):从根节点开始,依次顺着word中的字符一直向下走(如果不存在,则首先增加一个代表该字符的结点),直到到达末尾。最后将末尾字符的isTail的值置为true。
b.search(string word):和insert(string)的思路很像,从根节点开始,依次顺着word中的字符一直向下走,一旦发现不存在,则直接返回false。当到达末尾时,还要判断末尾结点的isTail是否为true。因为只有isTail为true的时候才返回true,否则说明该word只是Trie中的某个word的前缀,需要返回false。
c.startWith(string prefix):非常类似于search(string word),唯一的区别在于只要到达末尾结点就返回true,否则返回false。
代码:
class TrieNode {
public:
// Initialize your data structure here.
TrieNode() {
isTail = false;
for(int i = 0; i < 26; ++i)
data[i] = NULL;
}
bool isTail;
TrieNode* data[26];
};
class Trie {
public:
Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
void insert(string word) {
TrieNode* node = root;
for(auto c : word) {
if(node->data[c - 'a'] == NULL) {
node->data[c - 'a'] = new TrieNode();
}
node = node->data[c - 'a'];
}
node->isTail = true;
}
// Returns if the word is in the trie.
bool search(string word) {
TrieNode* node = root;
for(auto c : word)
{
if(node->data[c - 'a'] == NULL) {
return false;
}
node = node->data[c - 'a'];
}
return node->isTail;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix) {
TrieNode* node = root;
for(auto c : prefix) {
if(node->data[c - 'a'] == NULL) {
return false;
}
node = node->data[c - 'a'];
}
return true;
}
private:
TrieNode* root;
};
// Your Trie object will be instantiated and called as such:
// Trie trie;
// trie.insert("somestring");
// trie.search("key");