当你在处理一份重要文件时,假设你发现自己拼错了一个单词。手工查找和纠正这类错误是很困难的。现在我们来看看有趣的莱文斯坦距离:它可以测量将一个序列转换成另一个序列所需的工作量,为序列比较和错误修复提供了有效的工具。这种以数学家弗拉基米尔·莱文斯坦命名的测量方法,改变了我们处理 DNA 测序和拼写检查等工作的方式。在准确性和精确性至关重要的数字时代,它是必不可少的。
什么是莱文斯坦距离?
俄罗斯科学家弗拉基米尔·莱文斯坦在1965年提出这个概念。
莱文斯坦距离(Levenshtein Distance)量化两个序列之间的差异程度,是编辑距离的一种。通过计算将一个序列转换成另一个序列所需的最少操作,它可以量化这种差异。允许进行以下操作:
- 插入:在序列中添加一个字符。
- 删除:从序列中删除一个字符。
- 替换:用一个字符替换另一个字符。
它是如何工作的?
我们采用基于矩阵的动态编程方法来确定两个字符串之间的莱文斯坦距离。下面是详细步骤:
矩阵初始化
- 创建一个矩阵,其中包含第一个字符串的前 i 个字符。然后第二个字符串的前 j 个字符用单元格 (i, j) 表示。
- 初始化第一行和第一列。单元格 (i, 0) 中的值代表第一个字符串的前 i 个字符与空的第二个字符串(即 i)之间的距离。同样,(0, j) 表示空的第一字符串与第二字符串的前 j 个字符之间的距离。
填充矩阵
- 对于每个单元格 (i,j),确定三个操作的成本:
插入:单元格(i,j-1)的值 + 1
删除:单元格(i-1,j)的值 + 1
替换:单元格(i-1,j-1)中的值加上成本,不同字符的成本为 1,相同字符的成本为 0。
- 从这三个选项中选择最低值,并将其分配到相应的单元格 (i, j)。
提取结果
- 矩阵右下角单元格中的值代表两个字符串之间的莱文斯坦距离。
示例
现在计算字符串 kitten 和 sitting 之间的莱文斯坦距离。
初始化矩阵
- 行代表 kitten 字符串中的字符。
- 列代表 sitting 字符串中的字符。
- 第一行和第一列根据索引填充(代表插入或删除操作)。
填充矩阵
- 比较字符,并根据插入、删除或替换的最小成本填充每个单元格。
计算距离
- 填入矩阵后,右下角的单元格会显示距离。
详细的分步计算
首先,使用 kitten(6 个字符)和 sitting(7 个字符)这两个字符串的长度创建矩阵。然后,使用插入、删除和替换方法填充矩阵。
初始化矩阵:初始矩阵的第一行和第一列填入了索引,看起来像这样:
图片
填充矩阵:插入、删除或替换是用于填充每个单元格(i,j)的三种操作。让我们逐一介绍每个单元格的操作步骤。
比较 “k”(小猫)和 “s”(坐):
- 插入 “k”:成本 = 2 (1 + 1)
- 删除 “s”:成本 = 2 (1 + 1)
- 用 “s” 代替 “k”:成本 = 1 (0 + 1)
- 最低成本 = 1(替代)
图片
继续以类似方式填写每对字符的矩阵:
图片
最终矩阵说明
- 第一行:表示通过删除将 kitten 转换为空字符串。
- 第一列:表示通过插入将空字符串转换为 sitting。
- 矩阵单元格:表示将 kitten 前缀转换为 sitting 前缀的成本。
右下方的单元格(7,7)表示整个 kitten 和 sitting 之间的列文斯泰因距离为 3。这表明将 kitten 转换为 sitting 需要进行三次操作(替换和插入)。
结论
通过计算将一个序列转换成另一个序列所需的修改次数,莱文斯坦距离为评估序列相似性提供了一个有用的指标。它是序列比较和纠错的重要工具,应用范围从遗传研究到拼写检查。理解和实施这一思想有助于解决序列转换和相似性起关键作用的实际问题。