编辑距离

编辑距离是指两个子串之间,由一个转成另一个所需要的最少编辑操作次数。允许的编辑操作包括:

  • 将一个字符替换成另一个字符

  • 插入一个字符

  • 删除一个字符

这是常见的求两个字符编辑距离的题目描述,被称为莱文斯坦距离,又称为Levenshtein距离,是俄罗斯科学家莱温斯坦在1965年提出来的概念。 – 来自于维基百科

定义
假设两个字符串分别为A,B,长度分别为 n = ∣ A ∣ n=\left| A \right| n=A m = ∣ B ∣ m=\left| B \right| m=B,那么它们的莱文斯坦距离为 l e v A , B ( n , m ) lev_{A,B} \left(n, m \right) levA,B(n,m)。公式定义为:
l e v A , B ( i , j ) = { m a x ( i , j ) i f    m i n ( i , j ) = 0 m i n { l e v A , B ( i − 1 , j ) + 1 l e v A , B ( i , j − 1 ) + 1 l e v A , B ( i − 1 , j − 1 ) + I A i ≠ B j o t h e r s i z e lev_{A,B} \left(i, j \right) = \left\{\begin{matrix} max \left( i, j \right) & if \; min\left( i, j \right)=0 \\ min \left\{\begin{matrix} lev_{A,B} \left( i -1 , j \right) + 1 \\ lev_{A,B} \left( i , j -1 \right) + 1 \\ lev_{A,B} \left( i -1 , j - 1 \right) + I_{A_{i} \neq B_{j}} \end{matrix}\right. & othersize \end{matrix}\right. levA,B(i,j)=max(i,j)minlevA,B(i1,j)+1levA,B(i,j1)+1levA,B(i1,j1)+IAi=Bjifmin(i,j)=0othersize
其中 l e v A , B ( i , j ) lev_{A,B} \left( i, j \right) levA,B(i,j)表示的字符串A的前 i i i个字符与字符串B的前 j j j个字符之间的莱文斯坦距离;
l e v A , B ( i − 1 , j ) lev_{A,B} \left( i - 1, j \right) levA,B(i1,j) 表示删除字符
l e v A , B ( i , j − 1 ) lev_{A,B} \left( i, j - 1 \right) levA,B(i,j1) 表示插入字符
l e v A , B ( i − 1 , j − 1 ) lev_{A,B} \left( i -1 , j - 1 \right) levA,B(i1,j1) 表示字符替换
I A i ≠ B j I_{A_{i} \neq B_{j}} IAi=Bj是指示函数, A i A_{i} Ai B j B_{j} Bj相等时,取值为0,否则,取值为1。

上述是数学描述,真正代码实现时,由上述的公式可以很清晰地列出动态规划方程。假设字符串 A = “ h o r s e ” A=“horse” A=horse n = 5 n=5 n=5;字符串 B = “ r o s ” B=“ros” B=ros。设编辑数组为dp,数据初始化如下表形式。

A/B0123
00123
11
22
33
44
55

表示的是一个空字符串与字符串 A A A或字符串 B B B子串之间的编辑距离。

初始化之后,就需要计算字符串 A A A中第 i i i个字符 A i A_{i} Ai与字符串B中第 j j j个字符 B j B_{j} Bj的编辑距离了。比较 A i A_{i} Ai B j B_{j} Bj

  • 如果 A i A_{i} Ai B j B_{j} Bj相等,那么 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j] = dp[i-1][j-1] dp[i][j]=dp[i1][j1],无需任何操作;

  • 如果 A i A_{i} Ai B j B_{j} Bj不相等,那么就要比较三种操作(删除,插入和替换)哪一种更优惠,那么用公式表示就是: d p [ i ] [ j ] = 1 + m i n ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] ) dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) dp[i][j]=1+min(dp[i1][j],dp[i][j1],dp[i1][j1])

计算完之后,我们所给的例子字符串 A = “ h o r s e ” A=“horse” A=horse B = “ r o s ” B=“ros” B=ros最后生成的dp数组如下表所示,我们将操作所在的位置加粗显示。 d p [ 5 ] [ 3 ] = 3 dp[5][3] = 3 dp[5][3]=3,字符串A向B至少需要三步,分别是:第一步:horse -> rorse (将 ‘h’ 替换为 ‘r’);第二步:rorse -> rose (删除 ‘r’);第三步:rose -> ros (删除 ‘e’)。

A/B0123
00123
11123
22212
33222
44332
55443
class Solution {
public:
    int minDistance(string word1, string word2) {
        int len_1 = word1.length();
        int len_2 = word2.length();
        vector<vector<int>> dp(len_1+1, vector<int>(len_2+1, 0));
        for(int i=0;i<len_1+1;i++){
            dp[i][0] = i;
        }
        for(int j=0;j<len_2+1;j++){
            dp[0][j] = j;
        }
        for(int i=0;i<len_1;i++){
            for(int j=0;j<len_2;j++){
                if(word1[i] == word2[j]){
                    dp[i+1][j+1] = dp[i][j];
                }else{
                    int min_tmp = dp[i][j+1] < dp[i+1][j] ? dp[i][j+1] : dp[i+1][j];
                    min_tmp = min_tmp < dp[i][j] ? min_tmp : dp[i][j];
                    dp[i+1][j+1] = min_tmp + 1;
                }
            }
        }
        return dp[len_1][len_2];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马鹤宁

谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值