题目来源:牛客网链接:https://www.nowcoder.com/questionTerminal/9649617be3bf42288f50758df4310655
UNIX系统下有一个行编辑器ed,它每次只对一行文本做删除一个字符、插入一个字符或替换一个字符三种操作。例如某一行的内容是“ABC”,经过把第二个字符替换成“D”、删除第一个字符、末尾插入一个字符“B”,这三步操作后,内容就变成了“DCB”。即“ABC”变成“DCB”需要经过3步操作,我们称它们的编辑距离为3。
现在给你两个任意字符串(不包含空格),请帮忙计算它们的最短编辑距离。
输入描述:
输入包含多组数据。
每组数据包含两个字符串m和n,它们仅包含字母,并且长度不超过1024。
输出描述:
对应每组输入,输出最短编辑距离。
示例1
输入
ABC CBCD
ABC DCB
输出
2
3
分析:
假设序列S和T的长度分别为m和n, 两者的编辑距离表示为dp[m][n]. 则对序列进行操作时存在以下几种情况:
- a, 当S和T的末尾字符相等时, 对末尾字符不需要进行上述定义操作中(亦即"编辑")的任何一个, 也就是不需要增加计数. 则满足条件: dp[m][n] = dp[m - 1][n - 1].
- b, 当S和T的末尾字符不相等时, 则需要对两者之一的末尾进行编辑, 相应的计数会增加1.
- b1, 对S或T的末尾进行修改, 以使之与T或S相等, 则此时dp[m][n] = dp[m - 1][n - 1] + 1;
- b2, 删除S末尾的元素, 使S与T相等, 则此时dp[m][n] = dp[m - 1][n] + 1;
- b3, 删除T末尾的元素, 使T与S相等, 则此时dp[m][n] = dp[m][n - 1] + 1;
- b4, 在S的末尾添加T的尾元素, 使S和T相等, 则此时S的长度变为m+1, 但是此时S和T的末尾元素已经相等, 只需要比较S的前m个元素与T的前n-1个元素, 所以满足dp[m][n] = dp[m][n - 1] + 1;
- b5, 在T的末尾添加S的尾元素, 使T和S相等, 此时的情况跟b4相同, 满足dp[m][n] = dp[m - 1][n] + 1;
- c, 比较特殊的情况是, 当S为空时, dp[0][n] = n; 而当T为空时, dp[m][0] = m; 这个很好理解, 例如对于序列""和"abc", 则两者的最少操作为3, 即序列""进行3次插入操作, 或者序列"abc"进行3次删除操作.
所以, 以上我们不难推出编辑距离的动态规划方程为:
以字符串str1="ALGORITHM",str2="ALTRUISTIC"为例,m=strlen(str1)=9,n=strlen(str2)=10,最小编辑距离推导过程如下,先计算dp[1][1],dp[1][2]...dp[1][10],再计算dp[2][1]...dp[2][10]...。最终最小编辑距离=dp[m][n]=6.
代码如下:
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>//min()包含头文件
using namespace std;
int main(){
char str1[1025],str2[1025];长度不超过1024,长度最小要声明为1024+1,因为字符串末尾有空字符。
int n,m,temp;
while(cin>>str1>>str2){//循环输入两个字符串
m=strlen(str1);
n=strlen(str2);
vector<vector<int>> dp(m+1,vector<int>(n+1,0));//生成一个m+1行n+1列的二维矩阵记录当前的状态值
//初始化
for(int i=1;i<=m;i++)//dp[i][0]=i,例如dp[2][0]表示一个长度为2的字符串str1与一个空字符串str2的最小编辑距离为2(即依次将str1中的字符添加到str2中)
dp[i][0]=i;
for(int j=0;j<=n;j++)//dp[0][j]=j,例如dp[0][1]表示一个空字符串str1与一个长度为1的字符串str2的最小编辑距离为1(即依次将str2中的字符添加到str1中)
dp[0][j]=j;
dp[0][0]=0;//空字符串与空字符串之间的最小编辑距离为0
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(str2[j-1]==str1[i-1])//注意:字符串str1和str2中的索引是从0开始的,而1<=i<=m,1<=j<=n,所以这里的i和j要减1
dp[i][j]=dp[i-1][j-1];
else{
temp=min(dp[i][j-1],dp[i-1][j]);
dp[i][j]=min(temp,dp[i-1][j-1])+1;
}
}
}
cout<<dp[m][n]<<endl;//最终的dp[m][n]为两字符串之间的最小编辑距离
}
return 0;
}