【刷题之路】字符串的编辑距离

时间:2021-03-12 18:41:55

对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。

给定两个字符串AB,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。

经典动态规划问题,简历一个二维数组来解决问题

首先确定初始状态,先建立一个m+1*n+1的二维数组,其中行数是B,列数是A,数组的左上角为A,B都为空字符串时,显然操作数为0,对于第一行,显然是当B为空时,不断扩大A时所需要的操作,显然需要不断删除A中元素来达到,所以第一行里的操作数为i*c1,同理对于第一列,A为空不断扩大B,则需要不断将B中字符插入A中,所以第一列的操作数为i*c0。初始状态设置完毕

对于数组中某一个res[i][j]来说,可能的状态一共有四种,

1、对于当前A来说,删除一个字符,然后将删除后的字符字符串再去变为当前B,而删去一个字符之后,变为B的最小操作数为res[i][j-1],即res[i][j]=res[i][j-1]+c1;

2、对于当前A来说,插入一个字符,然后将插入后的字符串再去变为当前B,插入一个字符后最小操作数,为res[i-1][j](注:这里需要理解,前两种操作的本质实际上是字符串对齐,也就是说让这之前的字符串全部相等,然后再去考虑后面的,例如这个插入操作,并不是res[i][j+1],因为我是要将A变为B,所以当插入一个字符后,应该将当前的A与上一个B的最小操作数返回,因为假如需要插入的话,必然是A短,加入了一个字符后应该基于没加入字符时的状态的B比较,也就是res[i-1][j])即res[i][j]=res[i-1][j]+c0;

3、对于当前A来说,替换一个字符,然后将替换后的字符串再去变为B,即res[i][j]=res[i-1][j-1]+c2,

4、对与当前A来说,如果与当前B字符相同,可以考虑不变化,即res[i][j]=res[i-1][j-1](3与4实际上是二选一,因为我们需要的是最小的操作数)

取四种操作数中最小的作为当前位置的值,代码如下

class MinCost {
public:
    int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
        // write code here
        vector<int> sub(n+1);
        vector<vector<int>> res(m+1,sub);
        int i,j,temp1,temp2,temp3;
        for(i=0;i<=n;i++){
            res[0][i]=i*c1;
        }
        for(i=0;i<=m;i++){
            res[i][0]=i*c0;
        }
        for(i=1;i<=m;i++){
            for(j=1;j<=n;j++){
                temp1=res[i][j-1]+c1;
                temp2=res[i-1][j]+c0;
                if(A[j-1]==B[i-1]) temp3=res[i-1][j-1];
                else temp3=res[i-1][j-1]+min(c2,c0+c1);
                res[i][j]=min(temp1,min(temp2,temp3));  
            }
        }
        return res[m][n];
    }
};