• 编辑距离问题 教学篇


    编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
    例如将kitten一字转成sitting:
    sitten (k->s)
    sittin (e->i)
    sitting (->g)
    所以kitten和sitting的编辑距离是3。俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。
    给出两个字符串a,b,求a和b的编辑距离。
     
    这题要分三种情况考虑:
    先设dp[i][j]为a中1~i的子串和b中1~j的子串的编辑距离。
    第一种情况,(由常识可得)a中1~i的子串可以由a中1~i-1的子串加上a[i]得到,b中1~j的子串可以由b中1~j-1的子串加上b[j]得到。如果我们知道了dp[i-1][j-1]=k,且a[i] != b[j],那么dp[i][j]就可以是k+1,即在原基础上修改a[i]变成b[j],多花费了1。如果a[i]== b[j],那dp[i][j]还是k。
    第二种情况,如果我们知道了dp[i-1][j]=k,那么我们可以考虑把a[i]删除掉,这样dp[i][j]就可以是k+1。
    第三种情况,如果我们知道了dp[i][j-1]=k,那么我们可以考虑把b[j]添加到a[i]后面,这样dp[i][j]就可以是k+1。
    综上,dp[i][j]取上述三种情况的最小值。
     
    另外,这题可以做个小优化,由于dp[i][j]只和dp[i-1][j],dp[i][j-1],dp[i-1][j-1]有关,可以把dp数组改成滚动数组dp[2][MAXN],这样可以有效降低空间复杂度
     
    代码测试处:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1183
    参考代码:
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <string>
    #include <stack>
    #include <map>
    #include <set>
    #include <bitset>
    #define X first
    #define Y second
    #define clr(u,v); memset(u,v,sizeof(u));
    #define in() freopen("data","r",stdin);
    #define out() freopen("ans","w",stdout);
    #define Clear(Q); while (!Q.empty()) Q.pop();
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int maxn = 1e3 + 10;
    const int INF = 0x3f3f3f3f;
    char str1[maxn], str2[maxn];
    int dp[maxn][maxn];//dp[i][j]代表str1中1~i的子串变成str2中1~j的子串的最小花费
    int main()
    {
        scanf("%s%s", str2 + 1, str1 + 1);
        int len1 = strlen(str1 + 1), len2 = strlen(str2 + 1);
        int Max = max(len1, len2);
        dp[0][0] = 0;
        for (int i = 1; i <= Max; i++)
            dp[i][0] = dp[0][i] = dp[i-1][0] + 1;//初始化
        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);//假设dp[i][j-1]和dp[i-1][j]已知,那么我们只要在里面找个最小的,在末尾添加上一个字符就是答案了
                dp[i][j] = min(dp[i][j], dp[i-1][j-1] + (str1[i] != str2[j]));//dp[i-1][j-1]已知的话,可以把str1[i]变成str2[j],此时如果str1[i]==str2[j],就无需花费,否则花费1
            }
    //    for (int i = 0; i <= len1; i++)
    //    {
    //        for (int j = 0; j <= len2; j++)
    //            printf("%d ", dp[i][j]);
    //        printf("
    ");
    //    }
        printf("%d
    ", dp[len1][len2]);
        return 0;
    }
  • 相关阅读:
    作业题---设计一个类,求和的方法,求乘积的方法
    PHP-----预定义数组和数组的函数
    PHP-----指针遍历
    PHP------定义数组,取值数组和遍历数组
    PHP---------生成随机数,日期时间函数
    PHP的字符串处理
    PHP的正则表达式常用应用
    PHP的正则表达式
    PHP---函数
    PHP分页查询中的条件查询
  • 原文地址:https://www.cnblogs.com/scaugsh/p/6395705.html
Copyright © 2020-2023  润新知