一开始自己定义了TrieNode结点,发现在这道题没有必要这样做。也算是熟悉了一下Trie树,在Trie树下面有一个指针数组,分别对应了a-z26个字母,用结点形式存储,再来一个bool控制自己是否是叶子结点(一整句话的结尾)。
insert操作:来一个node结点指向树的root,也就是this,遍历插入的整句话,如果当前结点的指针数组中没有该结点,那么就给这个结点在数组中对应的那一个位置新建一个结点。如果有,就不用操作。然后将node指向下一个结点。判断有无就是node->child[ch-'a']==null
,指向下一个就是node = node->next[ch-'a']
search操作:遍历整句话,如果当前结点的孩子有这个字符,就更新当前结点为该孩子,如果无,就false。遍历完成后,判断当前结点是否是叶子结点,如果是才是完整的一句话
startwith和上面类似,只是不用判断是否是叶子
/*class TrieNode{
public:
bool containKey(char c){
//如果c='a',那么就判断当前结点child数组中第0位是否为空
return child[c-'a'] == nullptr;
}
void setEnd(){
is_End = true;
}
bool isEnd(){
return is_End;
}
TreeNode* get(char c){
return child[c-'a'];
}
void put(TreeNode* node,char c){
child[c-'a'] = node;
}
private:
TreeNode* child[26] = {nullptr};
bool is_End = false;
};*/
class Trie {
public:
//前缀树应该是以树型来查找达到O(logn)复杂度的,维护公共前缀子串的树
/** Initialize your data structure here. */
Trie() {
isEnd = false;
fill(child,child+26,nullptr);
}
/** Inserts a word into the trie. */
void insert(string word) {
//this是一个对象,就是自己,测试用例一开始就定义了一个root结点,后面就是对root进行操作,root就是this,不要让this自己动手
Trie* node = this;//不要让root亲自动手
//按word的顺序往下插,如果有就不用插往下,如果没有就插入继续往下
for(int i = 0; i < word.length(); ++i){
//如果没有就put,有就无需任何操作,继续向下遍历
if(node->child[word[i]-'a'] == nullptr){
node->child[word[i]-'a'] = new Trie();
}
node = node->child[word[i]-'a'];
}
node->isEnd = true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
//和startwith类似,但是所有判断完成后,要判断当前node是否是end
Trie* node =this;
for(int i = 0; i < word.length(); ++i){
if(node->child[word[i]-'a'] != nullptr){
node = node->child[word[i]-'a'];
}
else{
return false;
}
}
return node->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie* node =this;
for(int i = 0; i < prefix.length(); ++i){
//如果有这个结点就继续向下找,如果没有就是错的
if(node->child[prefix[i] - 'a'] != nullptr){
node = node->child[prefix[i]-'a'];
}
else{
return false;
}
}
return true;
}
private:
bool isEnd;
Trie* child[26];
};
/**
* 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*的数组26个元素,以及一个bool值判断当前结点是否是尾结点,在插入的最后将node的isEnd设为true即可。
class Trie {
public:
//根据操作来选底层数据结构
//前缀树是根据树型来查找达到O(logn)复杂度的,维护公共前缀子串的树
/** Initialize your data structure here. */
Trie() {
isEnd = false;
}
/** Inserts a word into the trie. */
void insert(string word) {
//要将这个word插入在这个树上,依次查找,如果当前结点存在,就直接去那一个,如果当前结点不存在,就新建一个结点
Trie* node = this;
for(int i = 0; i < word.length(); ++i){
if(node->child[word[i]-'a'] == nullptr){
Trie* newNode = new Trie();
node->child[word[i]-'a'] = newNode;
}
node = node->child[word[i]-'a'];
}
node->isEnd = true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie* node = this;
for(int i = 0; i < word.length(); ++i){
if(node->child[word[i]-'a'] == nullptr) return false;
node = node->child[word[i]-'a'];
}
return node->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie* node = this;
for(int i = 0; i < prefix.length(); ++i){
if(node->child[prefix[i]-'a'] == nullptr) return false;
node = node->child[prefix[i]-'a'];
}
return true;
}
private:
//底层数据结构是一个数组,数组里存的26个Trie指针
//26个指针刚好对应26个字母,根据当前字母是啥,顺着这个指针找下去即可
Trie* child[26] = {nullptr};
bool isEnd;
};
/**
* 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);
*/