Python实现字典树

1 字典树的定义

字典树也称作前缀树或者Trie树,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。(引自百度百科《字典树》)

2 字典树的特点

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符;
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
  3. 每个节点的所有子节点包含的字符都不相同。

3 字典树数据结构的实现方法

一个字典树要实现以下两种基本功能:

  1. 插入单词
  2. 搜索单词
  3. 搜索前缀
class Trie:
    def __init__(self):
        self.child = {}

    def insert(self, word):
        a = self.child
        for i in word:
            if not i in a.keys():
                a[i] = {}
            a = a[i]
        a["end"] = True
        
    def search(self, word):
        a = self.child
        for i in word:
            if not i in a.keys():
                return False
            a = a[i]
        return True if "end" in a.keys() else False
    
    def startsWith(self, prefix):
        a = self.child
        for i in prefix:
            if not i in a.keys():
                return False
            a = a[i]
        return True

4 字典树的应用

问题1:
设计一个支持以下两种操作的数据结构:
void addWord(word)
bool search(word)
search(word) 可以搜索文字或正则表达式字符串,字符串只包含字母 . 或 a-z 。 . 可以表示任何一个字母。
分析:
首先,该问题要求我们实现俩种功能,第一种功能就是一个基本的插入单词的功能,主要的问题其实集中在第二个功能。
那么第二个功能要求我们支持正则表达式的查询,可以用‘.’来代替任何一个字符。
在我们构建了字典树之后,在查询过程中,遇到了‘.’,那么我们要搜索该结点下的所有的子树,自然而然的,我们就能够想到要结合回溯法来解决这个问题。

代码实现:

class WordDictionary:

    def __init__(self):
        self.child = {}

    def addWord(self, word: str) -> None:
        temp = self.child
        for char in word:
            if char not in temp.keys():
                temp[char] = {}
            temp = temp[char]
        temp['end'] = True

    def search(self, word: str) -> bool:
        def dfs(temp, index):
            if index < len(word):
                if len(temp.keys()) == 0 or (len(temp.keys())==1 and 'end' in temp.keys()):
                    return False
            if index == len(word):
                return True if 'end' in temp.keys() else False
            if word[index] != '.':
                if word[index] not in temp.keys():
                    return False
                elif dfs(temp[word[index]], index + 1):
                    return True
            else:
                for key in temp.keys():
                    if key != 'end':
                        if dfs(temp[key], index + 1):
                            return True
            return False
        return dfs(self.child, 0)

问题2:

在英语中,我们有一个叫做词根(root)的概念,它可以跟着其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。
现在,给定一个由许多词根组成的词典和一个句子。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。
你需要输出替换之后的句子。
分析:
先根据词根,构造一个字典树。
然后将句子中的每个单词,都在字典树中搜索,若找到了匹配的前缀,则将单词替换成相应的词根即可。

代码实现:

class Solution:
    def replaceWords(self, dict: list, sentence: str) -> str:
        Trie = {}
        for root in dict:
            self.insert(Trie, root)
        result = []
        for word in sentence.split(" "):
            result.append(self.search_root(Trie, word))
        return " ".join(result) if result != [] else ""

    def insert(self, Trie, root):
        temp = Trie
        for char in root:
            if char not in temp.keys():
                temp[char] = {}
            temp = temp[char]
        temp['end'] = True
        
    def search_root(self, Trie, word):
        temp = Trie
        for index,char in enumerate(word):
            if char not in temp.keys():
                return word
            temp = temp[char]
            if 'end' in temp.keys():
                return word[:index+1]
        return word

问题3:

实现一个带有buildDict, 以及 search方法的魔法字典。
对于buildDict方法,你将被给定一串不重复的单词来构建一个字典。
对于search方法,你将被给定一个单词,并且判定能否只将这个单词中一个字母换成另一个字母,使得所形成的新单词存在于你构建的字典中。

分析:

主要的问题还是在search功能这块,问题要求是将单词中的一个字母替换为任意一个字母,然后替换后的单词,仍然存在于字典中。
首先,题目要求的替换次数是一次,且必定要进行一次替换。
那么,如果在字典树的某个结点中搜索时,我们要替换当前的字符c,有下列几种情况:
如果在该结点之前,我们已经进行过替换了,那么不能够再次替换。
如果该结点除了含有c字符的子树外,不存在任何别的结点,那么不可替换。
如果c并不是该结点的子树,且结点子树不为空,那么可以进行替换。
如果c是该结点的子树,并且该结点除了c子树,还有其他子树,那么可以进行替换。
使用回溯法来解决这个问题,并且用一个变量来记录是否进行过替换。

代码实现:

class MagicDictionary:

    def __init__(self):
        self.child = {}

    def buildDict(self, dict: list) -> None:
        for word in dict:
            temp = self.child
            for char in word:
                if char not in temp.keys():
                    temp[char] = {}
                temp = temp[char]
            temp['end'] = True

    def search(self, word: str) -> bool:
        def dfs(isModify, trie, index):
            if index == len(word):
                return True if (isModify and 'end' in trie.keys()) else False
            if word[index] in trie.keys():
                # not modify
                if dfs(isModify, trie[word[index]], index+1):
                    return True
                # modify
                if not isModify:
                    for key in trie.keys():
                        if key != word[index] and key != 'end':
                            if dfs(True, trie[key], index+1):
                                return True
            else:
                if isModify == True:
                    return False
                for key in trie.keys():
                    if key != word[index] and key != 'end':
                        if dfs(True, trie[key], index+1):
                            return True
            return False
        return dfs(False, self.child, 0)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值