leetcode之208前缀树
题目描述
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
示例:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 true
trie.search("app"); // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");
trie.search("app"); // 返回 true
说明:
- 你可以假设所有的输入都是由小写字母
a-z构成的。 - 保证所有输入均为非空字符串。
算法
核心思想就是在类中定义一个长度为26的指针数组,指向下一个结构体,每个结构体中又包含了判断当前结点是不是最后的结点和一个指向下一个结点的长度为26的指针数组。
需要注意的是在搜索search中,必须要在搜到被搜索字符串最后一个字符的时候在前缀树中刚好又是标记为最后一个字符的时候,才返回true
而在搜索前缀的时候,只要能够在前缀中将整个被搜索的前缀搜索完,就返回true,而不需要等到同时在前缀树中也是最后一个。
代码
class Trie {
public:
bool isEnd;
Trie *ptrs[26];
/** Initialize your data structure here. */
Trie() :isEnd(false),ptrs{nullptr}{
}
/** Inserts a word into the trie. */
void insert(string word) {
// 查找插入位置
Trie *cur=this;
for(size_t i=0;i<word.size();i++){
size_t index=word[i]-'a';
if(cur->ptrs[index]==nullptr){
cur->ptrs[index]=new Trie();
}
cur=cur->ptrs[index];
if(i==word.size()-1){
cur->isEnd=true;
}
}
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie *cur=this;
for(size_t i=0;i<word.size();i++){
size_t index=word[i]-'a';
if(cur->ptrs[index]==nullptr){
return false;
}else if(i==word.size()-1&&cur->ptrs[index]->isEnd){
return true;
}else if(i==word.size()-1&&!cur->ptrs[index]->isEnd){
return false;
}else{
cur=cur->ptrs[index];
}
}
return false;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie *cur=this;
for(size_t i=0;i<prefix.size();i++){
size_t index=prefix[i]-'a';
if(cur->ptrs[index]==nullptr){
return false;
}else if(i==prefix.size()-1){
return true;
}else{
cur=cur->ptrs[index];
}
}
return false;
}
~Trie(){
del(ptrs);
}
private:
void del(Trie *ptrs[26]){
for(size_t index=0;index<26;index++){
if(ptrs[index]!=nullptr){
del(ptrs[index]->ptrs);
delete(ptrs[index]);
ptrs[index]=nullptr;
}
}
}
};
因为在代码中用了new在堆中申请内存,所以我们需要自定义类的析构函数来释放在堆上申请的内存,释放的方式才用的是递归释放,我觉得这里可能会有一点问题,因为当字符串很长的时候,递归的深度就很长了。可以采用将递归转化为迭代的方式释放。就是使用深度搜索的方式。
浙公网安备 33010602011771号