遍历Trie以检查拼写建议的好算法是什么?

时间:2010-07-14 22:59:28

标签: algorithm spell-checking dynamic-programming trie

假设构建了一个普通的字典单词,那么检查4种拼写错误的最佳方法是什么 - 在遍历期间替换,删除,转置和插入?

一种方法是找出给定单词的n个编辑距离内的所有单词,然后在Trie中检查它们。这不是一个糟糕的选择,但这里更好的直觉似乎是使用动态编程(或递归等效)方法来确定在遍历期间修改单词后的最佳子尝试。

欢迎任何想法!

PS,会欣赏实际的输入,而不仅仅是答案中的链接。

4 个答案:

答案 0 :(得分:9)

前几天我实际上写了一些代码来执行此操作:

https://bitbucket.org/teoryn/spell-checker/src/tip/spell_checker.py

它基于Peter Norvig的代码(http://norvig.com/spell-correct.html),但是将字典存储在trie中,以便更快地查找给定编辑距离内的单词。

该算法通过消费输入字中的字母,在每个步骤中递归地应用可能的编辑(或不是)。递归调用的参数表示可以进行多少次编辑。 trie通过检查从我们给定的前缀实际可以到达哪些字母来帮助缩小搜索空间。例如,在插入字符时,我们只添加可从当前节点访问的字母,而不是添加字母表中的每个字母。不进行编辑等同于从输入字中的当前字母中取出trie中当前节点的分支。如果那个分支不在那里,那么我们可以回溯并避免搜索可能没有真正单词的大空间。

答案 1 :(得分:2)

我认为你可以通过树上直接的广度优先搜索来做到这一点:选择你要查找的错误数量的阈值,只需要一次一个地匹配单词的字母,生成到目前为止匹配前缀的一组(前缀,子组)对,当您低于错误阈值时,添加到您的下一个子目标集:

  1. 此角色位置没有错误:在单词中的下一个字符处添加trie的子目标
  2. 在此处插入,删除或替换字符:在那里找到合适的trie,并增加错误计数;
  3. 不是额外的目标,但请注意,换位是与早期删除或插入匹配的插入或删除:如果此测试成立,则不要增加错误计数。
  4. 这看起来很天真:这有什么问题导致你想到动态编程吗?

答案 2 :(得分:2)

假设你单词中的每个连续字符代表树中的一个级别,那么你有五个案例要检查每个字符(匹配,删除,插入,替换和转置)。我假设换位是两个相邻的字符。

您需要一个接受树节点和要检查的字符的函数(CheckNode)。它将需要返回一组表示匹配的(子/子)节点。

您需要一个接受单词的函数(CheckWord)。它依次针对一组节点检查每个字符。它将返回一组表示匹配单词的(叶子)节点。

这个想法是树中的每个级别(子级,孙子级等)都匹配单词中字符的位置。如果您调用顶级树节点,级别0,那么您将拥有级别1,级别2等。

显然,对于没有错误的单词,字符位置和树中的级别之间存在一对一的匹配。

对于删除,您需要跳过树中的级别。

对于插入,您需要跳过单词中的字符。

对于替换,您需要跳过级别和角色。

对于换位,您需要(暂时)交换单词中的字符。

答案 3 :(得分:1)

看看计算Levenshtein distance,它提供了一个动态编程解决方案,用于找到两个序列之间的距离。