使用Burkhard-Keller tree优化近似串匹配
source link: http://maskray.me/blog/2013-02-10-bk-tree
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
使用Burkhard-Keller tree优化近似串匹配
Approximate string matching
近似字符串匹配问题。
Levenshtein edit distance
在metric space中衡量两个字符串差异程度的一个指标,即通过一系列单字符的编辑操作把字符串A变成字符串B所需的最小编辑次数,其中的编辑操作可以是插入字符、删除字符以及修改字符。
计算编辑距离有个经典的Wagner-Fischer算法,使用了动态规划,用d(i,j)
表示把字符串A的前i
个字符变成字符串B的前j
个字符所需的最小编辑次数(即子串的编辑距离)。
下面给出Ruby实现:
另外,编辑距离是个metric,也就是说三个字符串间满足三角不等式:
dist(a, b) + dist(b, c) >= dist(a, c)
可以这样理解,把a
变成b
的最少修改操作和b
变成c
的最少修改操作拼起来就得到了把a
变成c
的一个可行修改操作,编辑次数为dist(a,c)
,而最小编辑次数肯定不会比这个数大。
Burkhard-Keller tree
给定一个字符串集合S
,有若干询问。每个询问的输入是一个字符串a
,输出是字符串集合S
中和a
的编辑距离在某个阈值内的所有字符串,即:{b | levenshtein(a,b) <= k}
,其中k
是阈值。
直观想法就是枚举S
中的每个串,一一和 a
求编辑距离,若在阈值内则输出。对于长为m
和n
的两个串,朴素的Wagner-Fischer算法时间复杂度是O(m*n)
,又要对集合中每个串都做这样的操作,比较慢。
于是就有两个优化策略:
优化编辑距离的计算
对于k
为常数的情况,可以利用性质d(a, b) >= abs(len(a)-len(b))
,动态规划表格中很多格子的值必然大于k
,而我们计算编辑距离的意图是判断是否在阈值内,所以对于这些值必然大于k
的格子我们是不感兴趣的,可以避免计算。我们只需要只计算一条diagonal band,这样可以把时间复杂度优化到O((m+n)*k)
。
另外对于这样的unit-cost Levenshtein edit distance问题,还可以采用一些bit-parallel方法进行常数优化。
减少字符串集合中的字符串枚举次数
令a
为字符串集合中任意一个字符串,对于询问字符串b
,计算出它们的编辑距离dist(a, b)
。对于每一个我们感兴趣的字符串c
,都满足dist(c,b) <= k
,而根据三角不等式,我们知道:
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK