力扣208——实现 Trie (前缀树)

这道题主要是构造前缀树节点的数据结构,帮助解答问题。

原题

实现一个 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?构成的。
  • 保证所有输入均为非空字符串。

原题url:https://leetcode-cn.com/problems/implement-trie-prefix-tree/

解题

前缀树的意义

我们用前缀树这种数据结构,主要是用在在字符串数据集中搜索单词的场景,但针对这种场景,我们也可以使用平衡树哈希表,而且哈希表可以在O(1)时间内寻找到键值。那为什么还要前缀树呢?

原因有3:

  1. 前缀树可以找到具有同意前缀的全部键值。
  2. 前缀树可以按词典枚举字符串的数据集。
  3. 前缀树在存储多个具有相同前缀的键时可以使用较少的空间,只需要O(m)的时间复杂度,其中 m 为键长。在平衡树中查找键值却需要O(m log n),其中 n 是插入的键的数量;而哈希表随着大小的增加,会出现大量的冲突,时间复杂度可能增加到O(n)

构造前缀树的节点结构

既然是树,肯定也是有根节点的。至于其节点结构,需要有以下特点:

  1. 最多 R 个指向子结点的链接,其中每个链接对应字母表数据集中的一个字母。本题中假定 R 为 26,小写拉丁字母的数量。
  2. 布尔字段,以指定节点是对应键的结尾还是只是键前缀。

接下来让我们看看节点结构的代码:

class TrieNode {

    TrieNode[] nodes;

    boolean isEnd;

    public TrieNode() {
        // 26个小写英文字母
        nodes = new TrieNode[26];
        // 当前是否已经结束
        isEnd = false;
    }

        /**
         * 当前节点是否包含字符 ch
         */
    public boolean contains(char ch) {
        return nodes[ch - 'a'] != null;
    }

        /**
         * 设置新的下一个节点
         */
    public TrieNode setNode(char ch, TrieNode node) {
            // 判断当前新的节点是否已经存在
        TrieNode tempNode = nodes[ch - 'a'];
                // 如果存在,就直接返回已经存在的节点
        if (tempNode != null) {
            return tempNode;
        }

        // 否则就设置为新的节点,并返回
        nodes[ch - 'a'] = node;
        return node;
    }

        /**
         * 获取 ch 字符
         */
    public TrieNode getNode(char ch) {
        return nodes[ch - 'a'];
    }

        /**
         * 设置当前节点为结束
         */
    public void setIsEnd() {
        isEnd = true;
    }

    /**
         * 当前节点是否已经结束
         */
    public boolean isEnd() {
        return isEnd;
    }
}

接下来就是真正的前缀树的结构:

class Trie {

    /**
         * 根节点
         */
    TrieNode root;

    /** Initialize your data structure here. */
    public Trie() {
        root = new TrieNode();
    }

    /** Inserts a word into the trie. */
    public void insert(String word) {
        TrieNode before = root;
        TrieNode node;
                // 遍历插入单词中的每一个字母
        for (int i = 0; i < word.length(); i++) {
            node = new TrieNode();
            node = before.setNode(word.charAt(i), node);
            before = node;
        }
                // 设置当前为终点
        before.setIsEnd();
    }

    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        TrieNode before = root;
        TrieNode temp;
                // 遍历查找
        for (int i = 0; i < word.length(); i++) {
            temp = before.getNode(word.charAt(i));
            if (temp == null) {
                return false;
            }
            before = temp;
        }
                // 且最后一个节点也是终点
        return before.isEnd();
    }

    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        TrieNode before = root;
        TrieNode temp;
                // 遍历查找
        for (int i = 0; i < prefix.length(); i++) {
            temp = before.getNode(prefix.charAt(i));
            if (temp == null) {
                return false;
            }
            before = temp;
        }
        return true;
    }
}

提交OK,执行用时:43 ms,内存消耗:55.3 MB,虽然只战胜了87.40%的提交,但试了一下最快的那个代码,和我这个方法在时间上基本没什么差别,应该是当初提交的时候测试用例没有那么多吧。

总结

以上就是这道题目我的解答过程了,不知道大家是否理解了。这道题目可能需要专门去理解一下前缀树的用途,这样可以有助于构造前缀树的结构。

有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。

https://death00.github.io/

公众号:健程之道

原文地址:https://www.cnblogs.com/death00/p/12164983.html

时间: 2024-12-12 14:05:50

力扣208——实现 Trie (前缀树)的相关文章

leetcode 208. 实现 Trie (前缀树)/字典树

实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert("apple");trie.search("apple"); // 返回 truetrie.search("app"); // 返回 falsetrie.startsWith("app"); // 返回 truetrie.insert(&q

leetcode 208. 实现 Trie (前缀树)

实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 true trie.search("app"); // 返回 false trie.startsWith("app"); // 返回 true trie.inser

第15个算法-实现 Trie (前缀树)(LeetCode)

解法代码来源 :https://blog.csdn.net/whdAlive/article/details/81084793 算法来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert("apple"

LeetCode 208.实现Trie(字典树) - JavaScript

??Blog :<LeetCode 208.实现Trie(字典树) - JavaScript> 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 true trie.search("app"); // 返回 false trie.

[Swift]LeetCode208. 实现 Trie (前缀树) | Implement Trie (Prefix Tree)

Implement a trie with insert, search, and startsWith methods. Example: Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // returns true trie.search("app"); // returns false trie.startsWith("app");

实现 Trie (前缀树)

实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert("apple");trie.search("apple"); // 返回 truetrie.search("app"); // 返回 falsetrie.startsWith("app"); // 返回 truetrie.insert(&q

【学习总结】数据结构-Trie/前缀树/字典树-及其最常见的操作

Trie/前缀树/字典树 Trie (发音为 "try") 或前缀树是一种树数据结构,用于检索字符串数据集中的键. 一种树形结构,是一种哈希树的变种. 典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高. 应用: 自动补全 END 原文地址:https://www.cnblogs.com/anliux/p/12590368.html

Poj 2001 (Trie 前缀树)

#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<map> #define MAXN 400010 #defi

UVa 11732 &quot;strcmp()&quot; Anyone? (左儿子右兄弟前缀树Trie)

题意:给定strcmp函数,输入n个字符串,让你用给定的strcmp函数判断字符比较了多少次. 析:题意不理解的可以阅读原题https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2832 字符串很多,又很长,如果按照题目的意思两两比较,肯定会TLE,所以要用前缀树(Trie)来解决,当然只是用简单的前缀树也会TLE的, 我们必须对其进行优化,看了