LeetCode(72)Edit Distance

本文详细解析LeetCode中的72题——编辑距离,介绍了如何通过动态规划求解从word1转换到word2所需的最小步骤数,并提供了状态转移方程及代码实现。编辑距离问题涉及到插入、删除和替换三种操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)
You have the following 3 operations permitted on a word:
a) Insert a character
b) Delete a character
c) Replace a character

本题是典型的适合使用动态规划的题目。在斯坦福的公开课(中文英文)上,有对这个问题的详细说明,所以接下来就继续使用斯坦福公开课的例子了。

如果要计算单词"INTENTION"和单词"EXECUTION"之间的编辑距离,那么该怎么计算呢?

首先,把这个问题简单化。把上面两个单词简化为长度为1的两个单词I和E。

如果要“I”变化为"E",可以把"I"替换为"E"
如果要“I”变化为空串" ",可以把"I"删除,从而形成""
如果要空串“ ”变化为"E",可以把"E"插入,从而形成E

上面三种变化分别表示替换,删除,插入这三种基本操作。

接下来,定义一个表达式D(i,j)。它表示从第1个字单词的第0位至第i位形成的子串和第2个单词的第0位至第j位形成的子串的编辑距离。

显然,可以计算出动态规划的初始表达式,如下:

D(i,0) = i

D(0,j) = j

然后,考虑动态规划的状态转移方程式,如下:

                                   D(i-1, j) + 1
D(i,j)=min                  ( D(i, j-1) + 1 )
                                   D(i-1, j-1) +2( if  X(i) != Y(j) ) ; D(i-1,j-1) ( if  X(i) == Y(j) )

上面的状态转移方程的含义是,D(i,j)的值,要么是D(i-1, j)的操作完成之后删除一个字符(第1个单词的第i个字符),要么是D(i, j-1)的操作完成之后增加一个字符(第2个单词的第j个字符),要么是D(i-1, j-1)的操作完成自后替换一个字符(如果第1个单词的第i个字符和第2个单词的第j个字符不等),或者是D(i-1, j-1)的操作完成自后什么也不做(如果第1个单词的第i个字符和第2个单词的第j个字符相等)。其中,课件定义删除,插入,替换的操作步数分别为一步,一步,两步。

以第一个单词"INTENTION"和第二个单词"EXECUTION"为例,看下面的图




接下来,代码实现。注意在leetcode中,把插入,删除,替换全部视为一步操作。

//new二维数组版本
class Solution {
public:
    int minDistance(string word1, string word2) {
        int len1=(int)word1.length()+1;
        int len2=(int)word2.length()+1;
        int** p=new int*[len1];
        if(!p){
            return 0;
        }

        for(int i=0;i<len1;i++){
            p[i]=new int[len2];
            if(!p[i]){
                return 0;
            }
        }
        for(int i=0;i<len1;i++){
            p[i][0]=i;
        }
        for(int j=0;j<len2;j++){
            p[0][j]=j;
        }
        for(int i=1;i<len1;i++){
            for(int j=1;j<len2;j++){
                int tmp_step;
                if( word1[i-1]==word2[j-1])//注意这里下标容易写错。一开始写成了if(word[i]==word2[j])
                    tmp_step=0+p[i-1][j-1];
                else
                    tmp_step=1+p[i-1][j-1];
                int tmp_step2=min((p[i-1][j]+1),(p[i][j-1]+1));
                p[i][j]=min(tmp_step2,tmp_step);
            }
        }
        
        return p[len1-1][len2-1];
    }

};

这个版本使用动态分配的二维数组,100ms通过测试。之前提交了一个版本,使用vector<vector<int>>来替代二维数组,编码简单一些,但是时间是220ms,说明STL确实会额外消耗一些时间。

//vector版本
class Solution {
public:
    int minDistance(string word1, string word2) {
        int len1=(int)word1.length()+1;
        int len2=(int)word2.length()+1;
        vector<vector<int>> dis_matrix;
        vector<int> tmp_vec;
        for(int j=0;j<len2;j++)
            tmp_vec.push_back(0);
        for(int i=0;i<len1;i++)
            dis_matrix.push_back(tmp_vec);
        
        for(int i=0;i<len1;i++)
            dis_matrix[i][0]=i;
        for(int j=0;j<len2;j++)
            dis_matrix[0][j]=j;
        
        for(int i=1;i<len1;i++){
            for(int j=1;j<len2;j++){
                int tmp_step;
                if( word1[i-1]==word2[j-1])//注意这里下标容易写错。一开始写成了if(word[i]==word2[j])
                    tmp_step=0+dis_matrix[i-1][j-1];
                else
                    tmp_step=1+dis_matrix[i-1][j-1];
                int tmp_step2=min((dis_matrix[i-1][j]+1),(dis_matrix[i][j-1]+1));
                dis_matrix[i][j]=min(tmp_step2,tmp_step);
            }
        }
        return dis_matrix[len1-1][len2-1];
    }

};

update: 2014-12-20

class Solution {
public:
    int minDistance(string word1, string word2) {
    vector<vector<int> > dp(word1.length() + 1, vector<int> (word2.length() + 1, 0));
    for (int i = 1; i <= word1.length(); ++i)
        dp[i][0] = i;
    for (int i = 1; i <= word2.length(); ++i)
        dp[0][i] = i;
    for (int i = 1; i <= word1.length(); ++i) {
        for (int j = 1; j <= word2.length(); ++j) {
                int replace_step = 0;
                if (word1[i - 1] == word2[j - 1])
                    replace_step = dp[i - 1][j - 1];
                else
                    replace_step = dp[i - 1][j - 1] + 1;
                replace_step = min(replace_step, dp[i - 1][j] + 1);
                dp[i][j] = min(replace_step, dp[i][j - 1] + 1);
        }
    }
    return dp[word1.length()][word2.length()];
    }
};


参考资料

斯坦福大学自然语言处理第三课“最小编辑距离(Minimum Edit Distance)

2 Stanford Natural Language Processing 


扩展小结:

1. edit distance 和 interleaving string这两道题目的共性是都用到了2D的 DP,都在处理String


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值