leetcode-208. 实现 Trie (前缀树)

题源

知识点

前缀树

  • 前缀树或者说是字典树,都是一个意思。
  • 它是一个多叉树
  • Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
  • 前缀树,对于大数据很有用,利用字符串的公共前缀来减少查询时间,最大限度地减少和字符串的直接比较
  • 这道题目的多叉树设计如下:

前缀树

思路

  • 就如上图的一样,isEnd判断是否存在单词,其余26个是一个指针数组,用空间换时间。
    +实现插入、搜索单词、搜索前缀
  • 如果存在这个单词,则将isEnd置为true,其他的时候都是为false。

代码

Python

class Trie:

    def __init__(self):
        self.children = [None] * 26
        self.isEnd = False

    def insert(self, word: str) -> None:
        node = self
        for w in word:
            index = ord(w) - ord('a')
            if not node.children[index]:
                node.children[index] = Trie()
            node = node.children[index]
        node.isEnd = True

    def search(self, word: str) -> bool:
        node = self
        for w in word:
            index = ord(w) - ord('a')
            if not node.children[index]:
                return False
            node = node.children[index]
        return node.isEnd

    def startsWith(self, prefix: str) -> bool:
        node = self
        for w in prefix:
            index = ord(w) - ord('a')
            if not node.children[index]:
                return False
            node = node.children[index]
        return True



# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

执行用时:180 ms, 在所有 Python3 提交中击败了51.04%的用户
内存消耗:33.6 MB, 在所有 Python3 提交中击败了37.97%的用户

JavaScript

var Trie = function() {
    this.isEnd = false
    this.children = new Array(26).fill(null)
};

/** 
 * @param {string} word
 * @return {void}
 */
Trie.prototype.insert = function(word) {
    let node = this
    for(let w of word){
        let index = w.charCodeAt(0) - 'a'.charCodeAt(0)
        if(!node.children[index])  node.children[index] = new Trie()
        node = node.children[index]
    }
    node.isEnd = true
};

/** 
 * @param {string} word
 * @return {boolean}
 */
Trie.prototype.search = function(word) {
    let node = this
    for(let w of word){
        let index = w.charCodeAt(0) - 'a'.charCodeAt(0)
        if(! node.children[index]) return false
        node = node.children[index]
    }
    return node.isEnd
};

/** 
 * @param {string} prefix
 * @return {boolean}
 */
Trie.prototype.startsWith = function(prefix) {
    let node = this
    for(let w of prefix){
        let index = w.charCodeAt(0) - 'a'.charCodeAt(0)
        if(! node.children[index]) return false
        node = node.children[index]
    }
    return true
};


/**
 * Your Trie object will be instantiated and called as such:
 * var obj = new Trie()
 * obj.insert(word)
 * var param_2 = obj.search(word)
 * var param_3 = obj.startsWith(prefix)
 */

执行用时:180 ms, 在所有 JavaScript 提交中击败了59.66%的用户
内存消耗:65.3 MB, 在所有 JavaScript 提交中击败了12.86%的用户

Java

class Trie {
    private boolean isEnd;
    private final Trie[] children;

    public Trie() {
        isEnd = false;
        children = new Trie[26];
    }

    public void insert(String word) {
        Trie node = this;
        int wordLen = word.length();
        for(int i = 0; i < wordLen; i++){
            int index = word.charAt(i) - 'a';
            if(node.children[index] == null){
                node.children[index] = new Trie();
            }
            node = node.children[index];
        }
        node.isEnd = true;
    }

    public boolean search(String word) {
        Trie node = this;
        int wordLen = word.length();
        for(int i = 0; i < wordLen; i++){
            int index = word.charAt(i) - 'a';
            if(node.children[index] == null){
                return false;
            }
            node = node.children[index];
        }
        return node.isEnd;
    }

    public boolean startsWith(String prefix) {
        Trie node = this;
        int wordLen = prefix.length();
        for(int i = 0; i < wordLen; i++){
            int index = prefix.charAt(i) - 'a';
            if(node.children[index] == null){
                return false;
            }
            node = node.children[index];
        }
        return true;
    }
}


/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */

执行用时:36 ms, 在所有 Java 提交中击败了38.80%的用户
内存消耗:49.6 MB, 在所有 Java 提交中击败了76.47%的用户

C

typedef struct {
    bool isEnd;
    struct Trie *children[26];
} Trie;


Trie* trieCreate() {
    Trie * t = (Trie *)malloc(sizeof(Trie));
    t->isEnd = false;
    for(int i = 0; i < 26; i++) t->children[i] = NULL;
    return t;
}

void trieInsert(Trie* obj, char * word) {
    int wordLen = strlen(word);
    for(int i = 0; i < wordLen; i++){
        int index = word[i] - 'a';
        if(obj->children[index] == NULL){
            obj->children[index] = trieCreate();
        }
        obj = obj->children[index];
    }
    obj->isEnd = true;
}

bool trieSearch(Trie* obj, char * word) {
    int wordLen = strlen(word);
    for(int i = 0; i < wordLen; i++){
        int index = word[i] - 'a';
        if(obj->children[index] == NULL){
           return false;
        }
        obj = obj->children[index];
    }
    return obj->isEnd;
}

bool trieStartsWith(Trie* obj, char * prefix) {
    int wordLen = strlen(prefix);
    for(int i = 0; i < wordLen; i++){
        int index = prefix[i] - 'a';
        if(obj->children[index] == NULL){
           return false;
        }
        obj = obj->children[index];
    }
    return true;
}

void trieFree(Trie* obj) {
    for(int i = 0; i < 26; i++){
        if(obj->children[i] != NULL){
            trieFree(obj->children[i]);
        }
    }
    free(obj);
}

/**
 * Your Trie struct will be instantiated and called as such:
 * Trie* obj = trieCreate();
 * trieInsert(obj, word);
 
 * bool param_2 = trieSearch(obj, word);
 
 * bool param_3 = trieStartsWith(obj, prefix);
 
 * trieFree(obj);
*/

执行用时:60 ms, 在所有 C 提交中击败了65.12%的用户
内存消耗:38.1 MB, 在所有 C 提交中击败了69.14%的用户

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值