使用字典树进行拼写纠正

应用

如何把单词存入一个字典来纠正拼写呢?对于某个给定的单词,我们希望很快在字典中找到一个最接近的词。如果把字典里的所有单词存在一个散列表里,单词之间的一切相近性信息都将丢失。所以,更好的方式是把这些单词存入字典树,字典树也叫前缀树或排序树(trie tree)。

定义

一棵保存了某个单词集合的树称为字典树。连接一个节点及其子节点的弧线用不同字母标注。因此,字典中的每个单词与树中从根节点到树节点的路径相关。每个节点都是标记,用于区分相关字母组合究竟是字典中的单词,还是字典中单词的前缀(图 2.2)。
在这里插入图片描述
字典树存储着法语单词 as、port、pore、pré、près 和 prêt(但没有重音符号)。图中的虚线圈表示子节点 [①] ;实线圈代表字典中一个完整的单词。右边是一个前缀树代表的相同字典 [②]。
① 这个路径的字母组合只是一个正确拼写的单词前缀。——译者注
② 右侧的树合并了只有一个子节点的路径,经过优化的结构更简洁,效率更高。——译者注

拼写纠正

利用上述数据结构,我们很容易在字典中找到一个与给定单词距离为 dist 的单词。这里的距离以 编辑距离(levenshtein distance)来定义,本书 3.2 节有详细介绍。查找方式是只需模拟每个节点的拼写操作,然后使用参数 dist-1 进行递归调用。

变种

若某个节点只有一个子节点,就可以合并多个节点,这种结构更精简。这种节点用单词标记,而不是用字母标记。图 2.2 右侧的结构更节省内存和遍历时间,被称为前缀树(patricia trie)。



class Trie_Node:
    def __init__(self):
        self.isWord = False
        self.s = {c: None for c in ascii_letters}
 
def add(T, w, i=0):
    if T is None:
        T = Trie_Node()
    if i == len(w):
        T.isWord = True
    else:
        T.s[w[i]] = add(T.s[w[i]], w, i + 1)
    return T
 
def Trie(S):
    T = None
    for w in S:
        T = add(T, w)
    return T
 
def spell_check(T, w):
    assert T is not None
    dist = 0
    while True:                              # 尝试用越来越长的距离来查找
        u = search(T, dist, w)
        if u is not None:
            return u
        dist += 1
 
def search(T, dist, w, i=0):
    if i == len(w):
        if T is not None and T.isWord and dist == 0:
            return ""
        else:
            return None
    if T is None:
        return None
    f = search(T.s[w[i]], dist, w, i + 1)           # 相关
    if f is not None:
        return w[i] + f
    if dist == 0:
        return None
    for c in ascii_letters:
        f = search(T.s[c], dist - 1, w, i)          # 插入
        if f is not None:
            return c + f
        f = search(T.s[c], dist - 1, w, i + 1)      # 替换
        if f is not None:
            return c + f
    return search(T, dist - 1, w, i + 1)            # 删除

作者:图灵教育
链接:https://leetcode-cn.com/leetbook/read/programmation-efficace/94bas5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在这里插入代码片

作者:图灵教育
链接:https://leetcode-cn.com/leetbook/read/programmation-efficace/94bas5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:图灵教育
链接:https://leetcode-cn.com/leetbook/read/programmation-efficace/94bas5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

*作者:图灵教育
链接:https://leetcode-cn.com/leetbook/read/programmation-efficace/94bas5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
字典树(Trie树)是一种树形数据结构,用于高效地存储和查找字符串集合。字典树的基本思想是,将每个字符串中的字符按照顺序依次插入到一棵树中,从根节点到叶子节点的路径上构成的字符串就是一个完整的字符串。 在进行字符串匹配时,我们可以利用字典树来快速地判断一个字符串是否存在于一个字符串集合中。具体的匹配过程如下: 1. 构建字典树。将所有的字符串按照顺序插入到一棵字典树中。 2. 遍历待匹配字符串中的每个字符,从字典树的根节点开始,依次查找对应的子节点。 3. 如果某个字符在当前节点的子节点中不存在,则说明待匹配字符串不存在于字符串集合中,直接返回false。 4. 如果待匹配字符串的所有字符都在字典树中存在对应的子节点,则说明待匹配字符串存在于字符串集合中,返回true。 下面是一个示例代码,用于实现基于字典树的字符串匹配: ```python class TrieNode: def __init__(self): self.children = [None] * 26 self.is_end_of_word = False class Trie: def __init__(self): self.root = TrieNode() def insert(self, word): node = self.root for c in word: index = ord(c) - ord('a') if node.children[index] is None: node.children[index] = TrieNode() node = node.children[index] node.is_end_of_word = True def search(self, word): node = self.root for c in word: index = ord(c) - ord('a') if node.children[index] is None: return False node = node.children[index] return node.is_end_of_word if __name__ == '__main__': trie = Trie() words = ["apple", "banana", "orange", "pear"] for word in words: trie.insert(word) print(trie.search("apple")) # True print(trie.search("pear")) # True print(trie.search("grape")) # False ``` 在上面的代码中,我们首先定义了一个TrieNode类,表示字典树中的节点。每个节点中包含一个长度为26的children数组,用于存储每个字符的子节点。同时,每个节点还有一个is_end_of_word标志,表示从根节点到当前节点的路径是否构成一个完整的单词。 接着,我们定义了一个Trie类,表示完整的字典树。在Trie类中,我们定义了两个方法,insert和search。其中,insert方法用于将一个单词插入到字典树中,search方法用于查找一个单词是否存在于字典树中。 在主函数中,我们首先创建了一个Trie对象,并将若干个单词插入到字典树中。然后,我们可以调用search方法来查找某个单词是否存在于字典树中。在上面的示例中,我们分别查找了"apple"、"pear"和"grape"这三个单词,结果分别为True、True和False。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值