一、问题描述

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括:(1)删除一个字符;(2)插入一个字符;(3)将一个字符改为另一个字符。

将字符串A变换为字符串B 所用的最少字符操作次数也称为字符串A到B 的编辑距离,记为 d(A,B)。 试设计一个有效算法,对任给的2 个字符串A和B,计算出它们的编辑距离d(A,B)。

算法设计:对于给定的字符串A和字符串B,计算距离d(A,B)。

数据输入:input.txt提供输入数据,第一行输入字符串A,第二行输入数据串B。输出结构,将d(A,B)的结果输入output.txt。

备注:题目来源——计算机算法设计与分析

二、原理分析

假设序列S和T的长度分别为m和n, 两者的编辑距离表示为edit[m][n]. 则对序列进行操作时存在以下几种情况:
A、当S和T的末尾字符相等时, 对末尾字符不需要进行上述定义操作中(亦即"编辑")的任何一个, 也就是不需要增加计数. 则满足条件: edit[m][n] = edit[m - 1][n - 1].
B、当S和T的末尾字符不相等时, 则需要对两者之一的末尾进行编辑, 相应的计数会增加1.
b1、对S或T的末尾进行修改, 以使之与T或S相等, 则此时edit[m][n] = edit[m - 1][n - 1] + 1;
b2、删除S末尾的元素, 使S与T相等, 则此时edit[m][n] = edit[m - 1][n] + 1;
b3、删除T末尾的元素, 使T与S相等, 则此时edit[m][n] = edit[m][n - 1] + 1;
b4、在S的末尾添加T的尾元素, 使S和T相等, 则此时S的长度变为m+1, 但是此时S和T的末尾元素已经相等, 只需要比较S的前m个元素与T的前n-1个元素, 所以满足edit[m][n] = edit[m][n - 1] + 1;
b5、在T的末尾添加S的尾元素, 使T和S相等, 此时的情况跟b4相同, 满足edit[m][n] = edit[m - 1][n] + 1;
C、比较特殊的情况是, 当S为空时, edit[0][n] = n; 而当T为空时, edit[m][0] = m; 这个很好理解, 例如对于序列""和"abc", 则两者的最少操作为3, 即序列""进行3次插入操作, 或者序列"abc"进行3次删除操作.
所以, 以上我们不难推出编辑距离的动态规划方程为:
编辑距离问题 随笔 第1张

其中,编辑距离问题 随笔 第2张

 

具体分析过程:

由编辑距离的动态规划方程我们可以看出, edit[m][n]可以由edit[m - 1][n - 1], edit[m - 1][n], edit[m][n - 1]得出, 而如果edit是一个二维数组的话, edit[m][n]可以由它的上, 左, 左上三个位置的元素通过条件判断得出. 亦即我们可以通过遍历二维数组, 然后通过回溯来计算当前值。

1、例如对于字符串S = "sailn"和T = "failing", 对二维数组进行初始化为:

 

 

编辑距离问题 随笔 第3张

2、因为S[0] = s, T[0] = f, 则S[0] != T[0], 则对应于上述二维矩阵, edit[1][1] = min(edit[0][0], edit[0][1], edit[1][0]) + 1即edit[1][1] = min(0, 1, 1) + 1即edit[1][1] = 0 + 1 = 1. 

 

 

编辑距离问题 随笔 第4张

3、而对于S[1] = a, T[1] = a, S[1] = T[1], 则对应于二维矩阵, edit[2][2] = edit[1][1], 所以edit[2][2] = 1. 所以按照这种规则, 将上述二维矩阵填满则如下:

编辑距离问题 随笔 第5张

4、所以, 两者的编辑距离为edit[m][n] = edit[5][7] = 3.

三、实现代码

 

#include <iostream>
#include <algorithm>// 调用min函数
#include <memory.h>
#include <cstdio>
#include <string>
using namespace std;

int num[1000][1000];
char str1[1000], str2[1000];
int min_three(int a, int b, int c) // 输出三个值中最小的值
{
	int temp = min(a, b);
	return min(temp, c);
}

int dist_edit(string str1, string str2)
{
	int i, j;
	int len1 = str1.length(), len2 = str2.length();
	for (i = 0; i < len1+1; i++)//对矩阵行列进行初始化
	{
		num[i][0] = i;
	}
	for (i = 0; i < len2+1; i++)
	{
		num[0][i] = i;
	}
	for (i = 1; i < len1+1; i++) {
		for (j = 1; j < len2+1; j++) {
			if (str1[i-1] == str2[j-1]) {
				num[i][j] = num[i - 1][j - 1];
			}
			else {
				num[i][j]=min_three(num[i][j - 1], num[i - 1][j - 1], num[i - 1][j]) + 1;
			}
		}
	}
	int return_value = num[len1 - 1][len2 - 1];
	return return_value;
}



int main()
{
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);

	cin >> str1 >> str2;

	cout << dist_edit(str1, str2) << endl;

	fclose(stdin);
	fclose(stdout);

	return 0;
}

  

 

四、补充

 本质是利用一个表,逐个对比,然后计算移位,得到最小操作数,明白实现原理之后,再变成实现,相对较为简单!

 重点是怎么用表去记性对比!

num[i][j]=min_three(num[i][j - 1], num[i - 1][j - 1], num[i - 1][j]) + 1;

 

参考链接——https://www.cnblogs.com/littlepanpc/p/7895810.html

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄