求两个字符串的编辑距离

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27901091/article/details/79540206

很多程序都需要利用到字符串的比较,而字符串的编辑距离在字符串相似性比较中,应用广泛。下面分享字符串编辑距离的求解。

概念
字符串的编辑距离,又称为Levenshtein距离,由俄罗斯的数学家Vladimir Levenshtein在1965年提出。是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数。其中,字符操作包括:

删除一个字符
插入一个字符
修改一个字符
例如对于字符串”if”和”iff”,可以通过插入一个’f’或者删除一个’f’来达到目的。

一般来说,两个字符串的编辑距离越小,则它们越相似。如果两个字符串相等,则它们的编辑距离(为了方便,本文后续出现的“距离”,如果没有特别说明,则默认为“编辑距离”)为0(不需要任何操作)。不难分析出,两个字符串的编辑距离肯定不超过它们的最大长度(可以通过先把短串的每一位都修改成长串对应位置的字符,然后插入长串中的剩下字符)。

问题描述
给定两个字符串A和B,求字符串A至少经过多少步字符操作变成字符串B。

问题分析
1)首先考虑A串的第一个字符

假设存在两个字符串A和B,他们的长度分别是lenA和lenB。首先考虑第一个字符,由于他们是一样的,所以只需要计算A[2…lenA]和B[2…lenB]之间的距离即可。那么如果两个字符串的第一个字符不一样怎么办?可以考虑把第一个字符变成一样的(这里假设从A串变成B串):

修改A串的第一个字符成B串的第一个字符,之后仅需要计算A[2…lenA]和B[2…lenB]的距离即可;
删除A串的第一个字符,之后仅需要计算A[2…lenA]和B[1…lenB]的距离即可;
把B串的第一个字符插入到A串的第一个字符之前,之后仅需要计算A[1…lenA]和B[2…lenB]的距离即可。
2)接下来考虑A串的第i个字符和B串的第j个字符。

我们这个时候不考虑A的前i-1字符和B串的第j-1个字符。如果A串的第i个字符和B串的第j个字符相等,即A[i]=B[j],则只需要计算A[i…lenA]和B[j…lenB]之间的距离即可。如果不想等,则:

修改A串的第i个字符成B串的第j个字符,之后仅需要计算A[i+1…lenA]和B[j+1…lenB]的距离即可;
删除A串的第i个字符,之后仅需要计算A[i+1…lenA]和B[j…lenB]的距离即可;
把B串的第j个字符插入到A串的第i个字符之前,之后仅需要计算A[i…lenA]和B[j+1…lenB]的距离即可。
写到这里,自然会想到用递归求解或者动态规划求解,由于用递归会产生很多重复解,所以用动态规划。

构建动态规划方程
用edit[i][j]表示A串从第i个字符开始和B串从第j个字符开始的距离。则从上面的分析,不难推导出动态规划方程:

,其中

#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
int dp[1010][1010];
int main(){
    FILE *fpread = fopen("p2.in.txt", "r");
    if (fpread == NULL) return 0;
    char str1[1010], str2[1010];
    fgets(str1, 1010, fpread); puts(str1);
    fgets(str2, 1010, fpread); puts(str2);
    int len1 = strlen(str1), len2 = strlen(str2);
    printf("%d %d", len1, len2);
    for (int i = 0; i < len1; i++){
        dp[i][0] = i;
    }
    for (int j = 0; j < len2; j++){
        dp[0][j] = j;
    }
    for (int i = 1; i < len1; i++){
        for (int j = 1; j < len2; j++){
            dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
            if (str1[i-1] == str2[j-1]){
                dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]);
            }
            else{
                dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]+1);
            }
        }
    }
    printf("%d", dp[len1 - 1][len2 - 1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27901091/article/details/79540206
今日推荐