定义
编辑距离又称Leveinshtein距离,是由俄罗斯科学家Vladimir Levenshtein在1965年提出。编辑距离是计算两个文本相似度的算法之一,以字符串为例,字符串a和字符串b的编辑距离是将a转换成b的最小操作次数,这里的操作包括三种:
- 插入一个字符
- 删除一个字符
- 替换一个字符
实现
用leva,b(i,j) 来表示a和b的Leveinshtein距离(i和j分别代表a和b的长度),则:
当min(i,j)=0时,leva,b(i,j)=max(i,j),一个字符串的长度为0,编辑距离自然是另一个字符串的长度 当ai=bj时,leva,b(i,j)=leva,b(i−1,j−1),比如xxcz和xyz的距离=xxc和xy的距离 否则,leva,b(i,j)为如下三项的最小值: leva,b(i−1,j)+1(删除ai),比如xxc和xyz的距离=xx和xyz的距离+1 leva,b(i,j−1)+1(插入bj),比如xxc和xyz的距离=xxcz和xyz的距离+1=xxc和xy的距离+1 leva,b(i−1,j−1)+1(替换bj),比如xxc和xyz的距离=xxz和xyz的距离+1=xx和xy的距离+1
用公式表示如下:
递归实现
用上面的公式可以很容易的写出递归实现:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
递归的实现比较简单,递归的思想是通过递归的形式,最终得到一个由不可继续分割(递归出口)的式子组成的表达式,最终会存在非常多的重复的不可继续分割的式子,造成大量的重复计算,所以很低效。
动态规划实现
递归是从后向前分解,那与之相对的就是从前向后计算,逐渐推导出最终结果,此法被称之为动态规划,动态规划很适用于具有重叠计算性质的问题,但这个过程中会存储大量的中间计算的结果,一个好的动态规划算法会尽量减少空间复杂度。
全矩阵
以xxc和xyz为例,建立一个矩阵,通过矩阵记录计算好的距离:
依据上面的公式可以继续推导出第二行:
继续迭代,直至推导出最终结果:
这个过程记录了所有中间结果,空间复杂度为O(n2) ,来看一下代码实现:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
两行
空间复杂度可以继续优化,我们计算当前行时,只依赖上一行的数据,所以我们只需要O(2n) 的空间复杂度,代码实现:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
单行
我们还可以进一步优化,其实只需要一行就可以了,计算当前格子时,只需要左、上、左上的值,左面的值可以直接得到,上面的值是当前格子修改前的旧值,也可以直接得到,左上角的值是左面格子修改前的旧值,需要暂存,这时空间复杂度为O(n) 。
代码实现:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
应用
编辑距离是基于文本自身去计算,没有办法深入到语义层面,可以胜任一些简单的分析场景,如拼写检查、抄袭侦测等,在我的工作中,该算法在数据聚合时有一定的运用。
参考
https://en.wikipedia.org/wiki/Levenshtein_distance
http://www.dreamxu.com/books/dsa/dp/edit-distance.html
http://www.dreamxu.com/books/dsa/dp/edit-distance.html
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者高爽和本文原始地址:http://ghsau.blogspot.my/2017/12/edit-distance.html。
没有评论:
发表评论