LeetCode 热题 HOT 100 第五十五天 208. 实现 Trie (前缀树) 中等题 用python3求解

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

请你实现 Trie 类:

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

示例:
输入:
[“Trie”, “insert”, “search”, “search”, “startsWith”, “insert”, “search”]
[[], [“apple”], [“apple”], [“app”], [“app”], [“app”], [“app”]]
输出:
[null, null, true, false, true, null, true]

解释
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

提示:
1 <= word.length, prefix.length <= 2000
word 和 prefix 仅由小写英文字母组成
insert、search 和 startsWith 调用次数总计不超过 3 * 10^4 次
LeetCode 热题 HOT 100 第五十五天 208. 实现 Trie (前缀树) 中等题 用python3求解_第1张图片
参考:指路
前缀树,又称字典树、Trie树。顾名思义,这是一个树结构,来快速检索前缀。最广泛的应用就是这里面的search操作,当你在检索的时候,搜索了某个前缀,搜索框就会自动给出一些高频出现的,以这个为前缀的单词,用户就不需要打全整个单词了。

我们看Trie的结构,如下,假设我们现在单词表中有[dog,dot,one,do,ok]。
LeetCode 热题 HOT 100 第五十五天 208. 实现 Trie (前缀树) 中等题 用python3求解_第2张图片
我们首先定义一个root结点作为开始,然后把五个单词每个字符按照顺序加入树。**每一个树节点的True表示从根节点到这个节点组成的单词在单词表中,我们可以知道,所有的叶节点都为True。**我们搜索do,发现最后o对应的结点为True,所以do这个单词存在。我们搜索on,n这个节点为Fasle,这个单词不存在。

对于insert操作,我们只要从根节点开始,按顺序对单词每个字符结点加入即可(如果已经存在了就忽略),对单词的最后一个字符的结点置为True。

对于startswith操作,我们只要判断这个前缀是不是按顺序存在即可,不需要考虑True和False,比如前缀on是存在的。

解法:字典(哈希表)
对于每个节点都是一个字典dict,它的键为后续的字符,值为这个字符对应的字典,同时对单词结尾的字符,我们添加一个键-1,如果-1在这个字典中,说明这个单词存在。整个结构相当于一层一层嵌套的字典,所以叫字典树。

代码实现:

class Trie:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        #初始化根节点
        self.root = dict()

    def insert(self, word: str) -> None:
        p = self.root # p是临时变量,通过p改变root(也就是树)
        #遍历word中所有字符
        for x in word:
            #如果x已经存在与p的键中了,说明x已经为p的后续字符了,pass
            #不存在,则对字符x创建一个字典,这个字典作为p中x对应的值
            if x not in p:
                p[x] = dict() # 插入app的时候不会进来这个if语句,因为已经有app这3个字符了
            p = p[x]
            # 插入apple的过程中全都是: p[x]:{}; p:{}。
            # 插入app:
            # x:a; p: {'p': {'p': {'l': {'e': {-1: True}}}}}
            # x:p; p: {'p': {'l': {'e': {-1: True}}}}
            # x:p; p {'l': {'e': {-1: True}}}

        #单词最后一个字符的单词,加一个键-1,对应值存不存在都无所谓,只要-1这个键存在,就代表是单词结尾
        p[-1] = True
        # 插入apple完成后: p:{-1: True},root:{'a': {'p': {'p': {'l': {'e': {-1: True}}}}}};
        # 插入app完成后: p:{'l':{'e':{-1:True}},-1:True},root:{'a': {'p': {'p': {'l': {'e': {-1: True}}, -1: True}}}},注意字母l和-1是同级的,也就是app后面跟l或-1

    def search(self, word: str) -> bool:
        p = self.root
        #开始遍历
        for x in word:
            if x in p:
                p = p[x]
            #如果路上不存在这个字符,直接Fasle
            else:
                return False
        #遍历到最后,还需要看-1存不存在
        if -1 in p:
            return True
        else:
            return False

    def startsWith(self, prefix: str) -> bool:
        """
        Returns if there is any word in the trie that starts with the given prefix.
        """
        #与上面search一样,只不过不需要看最后-1存不存在,因为不是找单词,是找前缀
        p = self.root
        for x in prefix:
            if x in p:
                p = p[x]
            else:
                return False
        return True

你可能感兴趣的:(LeetCode,热题,HOT,leetcode,数据结构,算法,力扣,python)