自学内容网 自学内容网

leetcode 208. 实现 Trie (前缀树)

Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word 。
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

基本做法:unordered_set<string>存储,前缀通过find实现

适用于 单词长度较小 

class Trie {
public:
    unordered_set<string> dp;
    Trie() {
        
    }
    
    void insert(string word) {
        if(!dp.count(word))
        {
           dp.insert(word);
        }
    }
    
    bool search(string word) {
        if(dp.count(word))
        {
            return true;
        }
        else return false;
    }
    
    bool startsWith(string prefix) {
        for(auto ie:dp)
        {
            if(ie.find(prefix)==0)
            {
                return true;
            }
        }
        return false;
    }
};

/**
 * 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);
 */

优点:插入,和查询的时间复杂度为O(1),内存占用小
缺点:多次前缀查询性能较低,时间复杂度为O(N*len) len为单词长度

26叉树实现

我们在Trie类种定义了一个26字母next表

适用于需要多次使用到前缀查询

字符插入

//当我们插入 apple对象时
当前Tire next全为空
第一个字符为a 
那我们 将next[0]创建好 
第二个字符 为p
那我们创建之前next[0]指向的next['p'-'a']
然后依次类推知道字符遍历完毕  我们就将这个字符插入到这个26叉数中 并且有利于前缀查询

void insert(string word) 
{
        auto temp=this;
        for(auto c:word)
        {
            c-='a';
            if(!temp->next[c]) temp->next[c]=new Trie();
            temp=temp->next[c];
        }
        temp->is_end=true;     //记录当前位置是一个单词的尾  和前缀区分开来以便serach
}

 查找辅助函数 

Trie* find_(string prefix)
{
     auto temp=this;
     for(auto c:prefix)
     {
         c-='a';
         if(temp->next[c]==nullptr)      //字符未遍历完但遇空 则表示没有相应的单词 
         {
             return nullptr;
         }
         temp=temp->next[c];
     }
     return temp;                       //返回prefix单词最后一个字符的next表
}

前缀查找prefix

找到前缀prefix 直接 return find_(predix)!=nullptr;

单词查找word

我们需要判断word最后一个字符的next表是否是 单词尾部 否则这个只是一个前缀 而不是单词本身

return find_(word)!=nullptr&&find_(wrod)->is_end==true;

完整代码:

class Trie {
public:
    vector<Trie*> next;
    bool is_end;
    Trie():next(26,nullptr),is_end(false){
    }
    Trie* find_(string prefix)
    {
        auto temp=this;
        for(auto c:prefix)
        {
            c-='a';
            if(temp->next[c]==nullptr)
            {
                return nullptr;
            }
            temp=temp->next[c];
        }
        return temp;
    }
    void insert(string word) {
        auto temp=this;
        for(auto c:word)
        {
            c-='a';
            if(!temp->next[c]) temp->next[c]=new Trie();
            temp=temp->next[c];
        }
        temp->is_end=true;
    }
    bool search(string word) {
         return find_(word)&&find_(word)->is_end==true;
    }
    
    bool startsWith(string prefix) {
         return find_(prefix)!=nullptr;
    }
};

/**
 * 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);
 */

 缺点:内存占用较高 单词的每一个字符都有next表 
优点:前缀查询快,单词查询较快,查询,插入时间复杂度均为O(len) len为单词长度


原文地址:https://blog.csdn.net/weixin_72492465/article/details/144009120

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!