我知道如何计算两个字符串之间的Levenshtein距离(感谢这个问题),它将给出一个得分,表示需要多少操作才能将一个字符串转换成另一个字符串。
假设我将“与另一个电子邮件地址非常接近”定义为两个字符串的Levenshtein得分小于N。
除了将每个可能的字符串与列表中的每个其他可能的字符串进行比较之外,是否有更有效的方法来查找得分低于此阈值的字符串对?换句话说,是否可以比
O(n^2)
更快地解决这种类型的问题?Levenshtein得分是解决此问题的不良算法选择吗?
O(n^2)
更快地解决这种类型的问题?是的 - 你可以使用BK-Tree在O(log n)时间内找到与给定距离内的所有字符串。对于Levenshtein距离为1的情况,生成每个距离为n的字符串的备选解可能会更快,但对于更长的距离,工作量会迅速膨胀。
m*n
,因此主对角线将在那里,(i,i),其中0 <= i < min(m,n)。 - Egon1
添加到距离中。因此,如果您从对角线超过k
次移开,则距离不会比k
更好。 - Egon我认为你无法做到比O(n^2)更好,但是你可以进行一些较小的优化,这些优化可能足以加速你的应用程序,使其可用:
编辑:实际上,您可以做得比O(n^2)更好,只需查看下面Nick Johnsons的答案即可。
如果反转问题,就有可能做得更好。
我假设你的10,000个地址相当“固定”,否则你将不得不添加更新机制。
这个想法是使用Levenshtein距离,但在Python中以“反向”模式进行:
class Addresses:
def __init__(self,addresses):
self.rep = dict()
self.rep[0] = self.generate_base(addresses)
# simple dictionary which associate an address to itself
self.rep[1] = self.generate_level(1)
self.rep[2] = self.generate_level(2)
# Until N
generate_level
方法从先前的集合中生成所有可能的变体,减去已经存在于前一个级别的变体。 它将“原点”保留为与键关联的值。
然后,您只需要在不同的集合中查找您的单词:
def getAddress(self, address):
list = self.rep.keys()
list.sort()
for index in list:
if address in self.rep[index]:
return (index, self.rep[index][address]) # Tuple (distance, origin)
return None
假设你有3个字符串:
1 - "abc" 2 - "bcd" 3 - "cde"
1和2之间的L距离为2(减去'a',加上'd')。 2和3之间的L距离为2(减去'b',加上'e')。
你的问题是我们是否可以通过使用上述2个比较来推断出1和3之间的L距离。答案是否定的。
1和3之间的L距离为3(替换每个字符),由于前两个计算的分数不揭示删除、插入或替换操作,因此无法推断出这一点。
因此,我认为Levenshtein对于大型列表来说是一个糟糕的选择。
1万个电子邮件地址听起来不算太多。如果要在更大的空间中进行相似性搜索,您可以使用shingling和min-hashing。这个算法实现起来有点复杂,但在大空间中效率更高。
如果你真的在比较电子邮件地址,那么一种明显的方法是将Levenshtein算法与域映射相结合。我可以想到有时候我会使用相同的域名但是电子邮件地址的用户名部分会有所变化,因此我会多次注册同一个东西。