LeetCode208. 实现 Trie (前缀树)

方法一

可以直接用一个数组trie存放所有插入的字符串,然后insert和startsWith操作只需要遍历trie数组,逐个判断即可。

代码:

class Trie {
public:
    vector<string> trie;
    /** Initialize your data structure here. */
    Trie() {

    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        trie.push_back(word);
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        for(const auto &s : trie) {
            if(s == word) {
                return true;
            }
        }
        return false;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        int size = prefix.size();
        for(const auto &s : trie) {
            if(s.size() >= size && s.substr(0, size) == prefix) {
                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);
 */

方法二

方法一并不是严格的trie树。

我们可以用一个结构体存放trie树的每个节点,每个节点最多可能有a~z共26个孩子,为了方便,我们都用整数表示;另外每个节点还需要记录它们是否是一个单词的结尾,
可以用一个布尔变量is_end表示。

插入的时候,从根节点(空)开始,看当前节点对应的孩子是否和现在这个字母匹配,如果匹配,就继续往下走,如果不匹配,就插入一个字母,实际上,这就是trie树。

搜索的时候同理,如果当前节点对应的孩子和现在查询的字母相同,就继续往下走,否则返回false,如果最后存在一条路径,从根节点到某个节点上的字母组合成了查询的字符串,
还需要看看结尾的字母的is_end变量是否为true,只有当路径存在且路径最后一个字母的is_end变量为true时表示搜索成功。

startsWith和搜索类似,只不过我们只需要找到路径即可,即使路径最后一个节点的is_end变量不为true也没关系,只要存在路径,就说明有单词是以字符串prefix开头的,返回true。

class Trie {
public:
    struct Node {
        Node* son[26];            //节点最多有26个孩子
        bool is_end;              //如果节点是某个单词的结尾,标记一下
    }*root;
    /** Initialize your data structure here. */
    Trie() {
        root = new Node();
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Node* p = root;                             //p表示我们当前是在哪个节点,最开始在根节点(空)
        for(int i = 0; i < word.size(); ++i) {      //从根节点开始逐层往下搜索
            int u = word[i] - 'a';
            if(p -> son[u] == NULL) {              //如果某节点不存在,则新建一个节点
                p -> son[u] = new Node();
            }
            p = p -> son[u];                        //继续往下走
        }
        p -> is_end = true;                         //标记一下这是一个单词的结尾
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Node* p = root;
        for(int i = 0; i < word.size(); ++i) {
            int u = word[i] - 'a';
            if(p -> son[u] == NULL) {
                return false;                        //如果没找到,返回false
            }
            p = p -> son[u];
        }
        return p -> is_end;                          //找到一条路径上的单词和word相同,还要看一下is_end变量是否为true,因为这可能是某个单词的前缀
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {                  //startsWith和search类似,唯一不同就是只要路径存在就返回true
        Node* p = root;
        for(int i = 0; i < prefix.size(); ++i) {
            int u = prefix[i] - 'a';
            if(p -> son[u] == NULL) {
                return false;
            }
            p = p -> son[u];
        }
        return true;
    }
};

/**
 * 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);
 */
posted @ 2020-08-13 16:09  machine_gun_lin  阅读(104)  评论(0编辑  收藏  举报