首页 > 代码库 > 计算字符串距离

计算字符串距离

编辑距离,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。Levenshtein距离可以通过下面这个状态方程求解:


这个式子还是比较好理解的:当字符串a为空,那么两个字符串之间的距离就是另一个字符串b的长度,因为可以通过删除strlen(b)个字符后编程空字符。其它三个方程类似。

在《编程之美》中使用了递归的方法,就是将上述方程原封不动的表示了出来,代码如下:

<span style="font-size:14px;">// 递归法计算字符串距离(Levenshtein距离)
int StringDistance(char *str1, char *str2)
{
	// str1、str2不能为NULL
	if (*str1 == '\0')
	{
		if (*str2 == '\0')
			return 0;
		else
			return strlen(str2);
	}
	if (*str2 == '\0')
	{
		if (*str1 == '\0')
			return 0;
		else
			return strlen(str1);
	}
	if (*str1 == *str2)
		return StringDistance(str1 + 1, str2 + 1);
	else
	{
		int d1 = StringDistance(str1 + 1, str2);		// str2增加一个字符
		int d2 = StringDistance(str1, str2 + 1);		// str2删除一个字符
		int d3 = StringDistance(str1 + 1, str2 + 1);	// str2修改一个字符
		return min(min(d1, d2), d3) + 1;
	}
}</span>

但这样的代码是存在重复计算的,改进后的动态规划方法使用一个二维数组保存中间变量,代码如下:

<span style="font-size:14px;">// 动态规划计算字符串距离(Levenshtein距离)
int StringDistance_DP(char *str1, char *str2)
{
	int len1 = strlen(str1);
	int len2 = strlen(str2);

	// D[i][j]表示str1[0]~str1[i-1]和str2[0]~str2[j-1]之间的字符串距离
	int **D = new int*[len1 + 1];
	for (int i = 0; i <= len1; i++)
		D[i] = new int[len2 + 1];

	// str2长度为0,距离为str1的长度
	for (int i = 0; i <= len1; i++)
		D[i][0] = i;

	// str1长度为0,距离为str2的长度
	for (int j = 0; j <= len2; j++)
		D[0][j] = j;

	for (int i = 1; i <= len1; i++)
	{
		for (int j = 1; j <= len2; j++)
		{
			// 若str1[i-1]和str2[j-1]相等,则距离不增加
			if (str1[i - 1] == str2[j - 1])
				D[i][j] = D[i - 1][j - 1];
			else
				// D[i][j - 1] + 1:删除str2[j-1],长度+1
				// D[i - 1][j] + 1:删除str1[i-1],长度+1
				// 若str1[i-1]和str2[j-1]不相等,则执行替换操作,距离+1
				D[i][j] = min(min(D[i][j - 1] + 1, D[i - 1][j] + 1), D[i - 1][j - 1] + 1);
		}
	}

	for (int i = 0; i <= len1; i++)
	{
		for (int j = 0; j <= len2; j++)
			cout << D[i][j] << ' ';
		cout << endl;
	}

	int res = D[len1][len2];
	for (int i = 0; i <= len1; i++)
		delete[] D[i];
	delete[] D;
	return res;
}</span>

当str1 = "Saturday",str2 = "Sunday"时,这样便形成如下矩阵:



程序运行结果和上面的矩阵相同,程序无误,右下角的3就是两个字符串的Levenshtein距离,这又是一个使用动态规划解题的典型例子。



参考:

维基百科:http://en.wikipedia.org/wiki/Levenshtein_distance

《编程之美》

计算字符串距离