编辑距离算法 Levenshtein Distance 学习笔记

是什么?

编辑距离算法(Edit Distance),即Levenshtein Distance,用于计算一个单词转换到另一个单词的最短距离(其转换的三种方法:删、插、替),此概念在1965年由俄罗斯科学家 弗拉基米尔·莱文斯坦(Levenshtein · Vladimir)提出,故称Levenshtein Distance。

前言导入

如果我们想把单词cat变成单词cut,该怎样去做呢?答案显而易见,我们只需要把"a"替换成"u"

但是,一旦遇到比较复杂的词,例如attention变成attitude,是不是需要几秒来观察了?正因如此,我们不妨让电脑帮我们来算一下

准备实践

现在,我们给定两个单词,word1word2,使用编辑距离的概念去探寻到它们转换所需的最小操作数

示例:
string word1 = "aptitude"
string word2 = "attitude"
过程:
aptitude -> attitude(将"p"替换为"t")
最短距离:1

记住最关键的三个操作:

  • 将一个字符替换成另外一个字符(Substitutions
  • 插入一个字符(Insertions
  • 删除一个字符(Deletions

我们可以设置一个D_{ij},这是什么意思呢?

例如我们要把Sun转换为Satur,既然要转换,就要取它们所有的字母,即Sun取前三个,Satur取前五个,此时我们可以表示成D_{35}了,是不是清楚了i和j是什么作用?

Sun转换为Satur需要3次操作,将at插入在S和u之间,把n替换为r。

此时我们就可以表示为D_{35} = 3

那么D_{ij}的定义为:word1的前   i  个字符 与 word2的前   j   个字符 转换所需的最短距离。

接下来让我们分解一下它

第一种情况,也是比较乐观的情况,即word1与word2的末尾字符相同:

 如果Word1i-1Word2j-1是相同的,那么我们可以直接说D_{ij} = D_{i-1j-1}

第二种情况没有这么乐观,即word1word2的末尾字符不相同:

这样我们就要分类讨论了,也就是插,删,替三种方法

首先我们先来看看插入:

我们假设word1相较于word2,末尾只需要再添加一个Y,使之与后者相同

接下来是删除:

我们假设word1相较于word2,末尾需要去掉X,使得word1的i-1个字符与word2的j个字符有着较高相似性

最后是替换:

我们假设word1相较于word2,除去末尾有着高度的相似性,我们只需将X替换为Y,使得word1的i-1个字符与word2的j-1个字符有着较高相似性

这样,我们得出了三个结论:

插:D_{i \, j-1}+1

删:D_{i-1 \, j} +1

替:D_{i-1 \, j-1} +1

它们都是D_{ij}的值,我们要在其中选择最小值,所以可以表示为

D_{ij} =\, min\left\{\begin{matrix} D_{i-1 \, j} +1 & \\ D_{i \, j-1} +1 & \\ D_{i-1 \, j-1} +1 & \end{matrix}\right.

是不是光看公式有些难以理解,让我们来使用可视化的观察。


 

我们先把它画成表格状的,根据我们上面得到的结论,可以画出一个:

第一种末尾相同的情况:

 第二种不相同的情况:

 再把它们套入上面的表格里面,是不是简单了很多?

首先,我们来看第一个格子,hr不相等,取最小值,也就是左上角的0,完成了一次替换操作,所以次数加一

 这样,每次都取最小值,遇到相等的取左上角数字不变,以此类推,我们可以得到这个图

 最终右下角的数字即我们所要求的最短距离,我们可以验证一下是不是3次

可以看到,绿色的是实质性的操作,蓝色表示没有操作,因为它们是相同的。

这样,是不是就理解了呢?

代码部分

使用C++实现

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 5;
int d[maxn][maxn];
void LevenshteinDistance(string word1,string word2){
	int len1 = word1.length();
	int len2 = word2.length();

	for (int i = 0; i <= len1; i++) {
		d[i][0] = i;
	}
	for (int i = 0; i <= len2; i++) {
		d[0][i] = i;
	}
	for (int i = 1; i <= len1; i++) {
		for (int j = 1; j <= len2; j++) {
			d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1);
			d[i][j] = min(d[i][j], d[i - 1][j - 1] + (word1[i - 1] != word2[j - 1]));
		}
	}
	cout << d[len1][len2] << endl;
}
int main() {
	string word1, word2;
	cin >> word1 >> word2;
	LevenshteinDistance(word1, word2);
	return 0;
}

总结

编辑距离算法是一个古老却又十分有效的算法,可以在日常应用中帮助我们做许多事,可以用其计算字符串的相似度,这对一些查重来说是非常有用的


第一次写文章,本人才疏学浅,若有不足之处请见谅

部分思路来源于网络

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值