字典树。
测试中有:aaaaaaaaaaa... 的输入,如果每个节点用定长数组存储孩子的话,那就是26^len的空间复杂度(len为输入的长度),内存会不够的。
所以用map<char, TrieNode*>保存其孩子。
第三遍(将第二遍中search和startsWith的行为抽象成searchNode方法):
struct TrieNode
{
map<char, shared_ptr<TrieNode>> children;
bool is_word = false;
};
class Trie
{
public:
Trie(): root(shared_ptr<TrieNode>(new TrieNode)) {}
// Inserts a word into the trie.
void insert(string word) const
{
if (word.empty())
{
return ;
}
auto node = root;
for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
{
if (node->children.find((word[i])) == node->children.end())
{
node->children[word[i]] = shared_ptr<TrieNode>(new TrieNode);
}
}
node->is_word = true;
}
// Returns if the word is in the trie.
bool search(string word) const
{
auto node = searchNode(word);
return node!=nullptr && node->is_word;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix) const
{
return searchNode(prefix) != nullptr;
}
private:
shared_ptr<TrieNode> searchNode(string word) const
{
auto node = root;
for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
{
if (node->children.find(word[i]) == node->children.end())
{
return nullptr;
}
}
return node;
}
shared_ptr<TrieNode> root;
};
第二遍(将第一次代码中的尾递归改成了迭代,速度从270ms提升到了200ms):
struct TrieNode
{
map<char, shared_ptr<TrieNode>> children;
bool is_word = false;
};
class Trie
{
public:
Trie(): root(shared_ptr<TrieNode>(new TrieNode)) {}
// Inserts a word into the trie.
void insert(string word) const
{
if (word.empty())
{
return ;
}
auto node = root;
for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
{
if (node->children.find((word[i])) == node->children.end())
{
node->children[word[i]] = shared_ptr<TrieNode>(new TrieNode);
}
}
node->is_word = true;
}
// Returns if the word is in the trie.
bool search(string word) const
{
// no special judge for empty word here
auto node = root;
for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
{
if (node->children.find(word[i]) == node->children.end())
{
return false;
}
}
return node->is_word;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix) const
{
auto node = root;
for (size_t i = 0; i < prefix.size(); node = node->children[prefix[i ++]])
{
if (node->children.find(prefix[i]) == node->children.end())
{
return false;
}
}
return true;
}
private:
shared_ptr<TrieNode> root;
};
第一遍:
class TrieNode
{
public:
// Initialize your data structure here.
TrieNode()
{
is_word = false;
}
void insert(const string& word)
{
if (!word.empty())
{
nodes[word.front()] =
nodes[word.front()] != nullptr ?
nodes[word.front()] : new TrieNode();
nodes[word.front()]->insert(word.substr(1));
} else
{
is_word = true;
}
}
bool search(string word)
{
if (!word.empty())
{
if (nodes[word.front()] == nullptr)
{
return false;
} else
{
return nodes[word.front()]->search(word.substr(1));
}
}
return is_word;
}
bool startsWith(string prefix)
{
if (!prefix.empty())
{
if (nodes[prefix.front()] == nullptr)
{
return false;
} else
{
return nodes[prefix.front()]->startsWith(prefix.substr(1));
}
}
return true;
}
// MLE!!!
// TrieNode* nodes[26];
map<char, TrieNode*> nodes;
bool is_word;
};
class Trie
{
public:
Trie()
{
root = new TrieNode();
}
// Inserts a word into the trie.
void insert(string word)
{
root->insert(word);
}
// Returns if the word is in the trie.
bool search(string word)
{
return root->search(word);
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix)
{
return root->startsWith(prefix);
}
private:
TrieNode* root;
};