python-leetcode 53.实现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


方法一:字典树

Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含以下字段:

指向子节点的指针数组 children,对于本题而言,数组长度为 26,即小写英文字母的数量。此时 children[0] 对应小写字母 a,children[1] 对应小写字母 b,...

布尔字段 isEnd,表示该节点是否为字符串的结尾

插入字符串

从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:

  • 子节点存在。沿着指针移动到子节点,继续处理下一个字符。
  • 子节点不存在。创建一个新的子节点,记录在 children 数组的对应位置上,然后沿着指针移动到子节点,继续搜索下一个字符

 重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点标记为字符串的结尾

查找前缀

从字典树的根开始,查找前缀。对于当前字符对应的子节点,有两种情况:

  • 子节点存在。沿着指针移动到子节点,继续搜索下一个字符。
  • 子节点不存在。说明字典树中不包含该前缀,返回空指针。
  • 重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符

 若搜索到了前缀的末尾,就说明字典树中存在该前缀。此外,若前缀末尾对应节点的 isEnd 为真,则说明字典树中存在该字符串。

例如:

假设字符串里面只有 a 和 b 两种字符。

insert:例如插入字符串 aab,相当于生成了一条移动方向为「左-左-右」的路径。标记最后一个节点为终止节点。再插入字符串 aabb,相当于生成了一条移动方向为「左-左-右-右」的路径。标记最后一个节点为终止节点。

search:例如查找字符串 aab,相当于查找二叉树中是否存在一条移动方向为「左-左-右」的路径,且最后一个节点是终止节点

startsWith:例如查找前缀 aa,相当于查找二叉树中是否存在一条移动方向为「左-左」的路径,无其他要求。

推广到 26 种字母,其实就是一棵 26 叉树,对于 26 叉树的每个节点,可以用哈希表,或者长为 26 的数组来存储子节点。

class Trie(object):

    def __init__(self):
        self.children=[None]*26 #一个长度为26的列表,代表26个小写英文字母的子节点初始时每个位置都是
        self.isEnd=False #标记当前节点是否是某个单词的结尾
    
    def searchPrefix(self,prefix):#用于查找以 prefix 开头的前缀是否存在
        node=self
        for ch in prefix:
            ch=ord(ch)-ord("a")# 计算字符ch在 children 列表中的索引(0-25)
            if not node.children[ch]:#说明前缀不存在
                return None
            node =node.children[ch]#继续检查下一个字符
        return node 

    def insert(self, word):
        """
        :type word: str
        :rtype: None
        """
        node=self
        for ch in word:
            ch=ord(ch)-ord("a")#将字符 ch 映射到 0 到 25 之间的索引
            if not node.children[ch]:#如果 children[ch] 为空,创建新的 Trie 节点,并存
                node.children[ch]=Trie()
            node=node.children[ch]#移动到下一个字符的子节点
        node.isEnd=True#标记 word 结束

    def search(self, word):
        """
        :type word: str
        :rtype: bool
        """
        node=self.searchPrefix(word)#查找 word 的最后一个节点
        return node is not None and node.isEnd#如果 node 不为 None,并且终结点存在,则存在树中,返回true,否则返回False


    def startsWith(self, prefix):
        """
        :type prefix: str
        :rtype: bool
        """
        #检查 Trie 树中是否有以 prefix 开头的单词
        return self.searchPrefix(prefix) is not None


# 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)

时间复杂度:初始化为 O(1),其余操作为 O(∣S∣),其中 ∣S∣ 是每次插入或查询的字符串的长度

空间复杂度:O(∣T∣⋅Σ),其中 ∣T∣ 为所有插入字符串的长度之和,Σ 为字符集的大小,本题 Σ=26。

源自灵茶山艾府

源自力扣官方题解
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值