7-3 编辑距离问题 (30 分)
 

设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括 (1)删除一个字符; (2)插入一个字符; (3)将一个字符改为另一个字符。 将字符串A变换为字符串B所用的最少字符操作数称为字符串A到 B的编辑距离,记为d(A,B)。 对于给定的字符串A和字符串B,计算其编辑距离 d(A,B)。

输入格式:

第一行是字符串A,文件的第二行是字符串B。

提示:字符串长度不超过2000个字符。

输出格式:

输出编辑距离d(A,B)

输入样例:

在这里给出一组输入。例如:

fxpimu
xwrs

输出样例:

在这里给出相应的输出。例如

5

——————————————————————————————————————分割线————————————————————————————————————————

解法:由于此题和经典的字符串查重有些许相似,考虑使用动态规划解法。

设一个二维数组edit[i][j],表示从前一个输入的串【before】0到i改到后一个输入的串【after】0到j要改的次数
当i=0,j=0,edit[i][j]=0;
当i=0或者j=0并另一个不为0,edit[][]=不为0的数【因为要加到i/j】

当两个尾数相等时候,edit[i][j]=edit[i-1][j-1]
当两个尾数不等,需要执行操作:
  1.换数:相当于做了一次操作的同时,要处理的i值j值都减1,edit[i][j]=edit[i][j-1]
  2.删数:相当于做了一次操作的同时,删哪行就哪个值减1,edit[i][j]=edit[i][j-1]or edit[i-1][j]
  3.加数:相当于做了一次操作的同时,由于加完数之后尾数相等,相当于另一行的值减1,edit[i][j]=edit[i-1][j] or edit[i][j-1]
由于操作最少,所以当然是这三种操作里面选最小的【min(min(edit[i-1][j]+1,edit[i][j-1]+1),edit[i-1][j-1]+1)】
再简化一下,可以改成if(before[i]==after[j])flag=0;else flag=1;
edit[i][j]=
min(edit[i-1][j]+1,edit[i][j-1]+1,edit[i-1][j-1]+flag)

填表得,i和j都递增
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
    char before[2000];
    char after[2000];
    int edit[2001][2001];
    cin>>before;
    cin>>after;
    edit[0][0]=0;
    int i,j;
    for(j=1;j<=strlen(after);j++)
    {
        edit[0][j]=j;
    }
    for(i=1;i<=strlen(before);i++)
    {
        edit[i][0]=i;
    }
    int f;
    for(i=1;i<=strlen(before);i++)
    {
        for(j=1;j<=strlen(after);j++)
        {
            if(before[i-1]==after[j-1])
            {
                f=0;
            }
            else f=1;
            edit[i][j]=min(min(edit[i-1][j-1]+f,edit[i][j-1]+1),edit[i-1][j]+1);
        }
    }
    cout<<edit[strlen(before)][strlen(after)];
}

时间复杂度:O(n)双重循环不解释

空间复杂度O(n)要创建辅助二维数组

感受:做题要取材但是不要拘泥于原算法(我一开始思路先查重记录每次字符相等的下标然后找规律然后想了两天都想出来...太惨了)现在这个正确算法实际思想和查重一样,但是具体步骤肯定不一样啊。

02-12 17:35