编辑距离算法(dp)

字符串编辑距离: 是一种字符串之间相似度计算的方法。给定两个字符串S、T,将S转换成T所需要的删除,插入,替换操作的数量就叫做S到T的编辑路径。而最短的编辑路径就叫做字符串S和T的编辑距离。

转自这里

 关键在于找到该问题的子问题。

举个例子:S=“eeba”   T="abac"   我们可以按照这样的步骤转变:(1) 将S中的第一个e变成a;(2) 删除S中的第二个e;(3)在S中最后添加一个c; 那么S到T的编辑路径就等于3。当然,这种变换并不是唯一的,但如果3是所有变换中最小值的话。那么我们就可以说S和T的编辑距离等于3了。

我们对最后一次的操作分析:

1.最后一次操作为copy。此时,根据题目的定义可知x[i]=y[j],我们待解决的问题就转化成了求将Xi-1转换为Yj-1的最小开销。将Xi-1转换为Yj-1的最优解一定包含在Xi转换为Yj的最优解内。用反证法证明:若存在从Xi-1到yj-1转换的更小的开销,那么用这个更小的开销来代替Xi-1转换为yj-1的最优解,这样就会得到一个更小的从Xi转换为Yj的开销,与已知的Xi转换为Yj的最优解矛盾,所以假设不成立。因此,当最后一次操作为copy时,可以定义c[i,j]=c[i-1,j-1]+cost(copy)。

2.最后一次操作为replace。此时,根据题目的定义可知x[i]≠y[j]。仿照上述分析,可以得到相同的最优子结构。此时c[i,j]=c[i-1,j-1]+cost(replace)。

3.最后一次操作为delete。根据题意,这时只是将x[i]从序列Xi中除去,对序列Yj没有任何影响,此时问题的最优子结构的形式为将Xi-1转换成Yj,于是可以得到c[i,j]=c[i-1,j]+cost(delete)。

4.最后一次操作为insert。根据题意,在进行插入操作时,序列Xi无任何变化,序列Yj添加一个字符,因此,这时候问题的最优子结构的形式为将Xi转换成为Yj-1,此时c[i,j]=c[i,j-1]+cost(insert)。

c语言代码(递归实现和动态规划实现):

// 动态规划实现 最小编辑距离
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

// 测试字符串
#define STRING_X "SUNDAY"
#define STRING_Y "SATURDAY"

#define SENTINEL (-1)
#define EDIT_COST (1)

inline
int min(int a, int b) {
   return a < b ? a : b;
}

// Returns Minimum among a, b, c
int Minimum(int a, int b, int c)
{
    return min(min(a, b), c);
}

// Strings of size m and n are passed.
// Construct the Table for X[0...m, m+1], Y[0...n, n+1]
int EditDistanceDP(char X[], char Y[])
{
    // Cost of alignment
    int cost = 0;
    int leftCell, topCell, cornerCell;

    int m = strlen(X)+1;
    int n = strlen(Y)+1;

    // T[m][n]
    int *T = (int *)malloc(m * n * sizeof(int));

    // Initialize table
    for(int i = 0; i < m; i++)
        for(int j = 0; j < n; j++)
            *(T + i * n + j) = SENTINEL;

    // Set up base cases
    // T[i][0] = i
    for(int i = 0; i < m; i++)
        *(T + i * n) = i;

    // T[0][j] = j
    for(int j = 0; j < n; j++)
        *(T + j) = j;

    // Build the T in top-down fashion
    for(int i = 1; i < m; i++)
    {
        for(int j = 1; j < n; j++)
        {
            // T[i][j-1]
            leftCell = *(T + i*n + j-1);
            leftCell += EDIT_COST; // deletion

            // T[i-1][j]
            topCell = *(T + (i-1)*n + j);
            topCell += EDIT_COST; // insertion

            // Top-left (corner) cell
            // T[i-1][j-1]
            cornerCell = *(T + (i-1)*n + (j-1) );

            // edit[(i-1), (j-1)] = 0 if X[i] == Y[j], 1 otherwise
            cornerCell += (X[i-1] != Y[j-1]); // may be replace

            // Minimum cost of current cell
            // Fill in the next cell T[i][j]
            *(T + (i)*n + (j)) = Minimum(leftCell, topCell, cornerCell);
        }
    }

    // 结果存储在 T[m][n]
    cost = *(T + m*n - 1);
    free(T);
    return cost;
}

// 递归方法实现
int EditDistanceRecursion( char *X, char *Y, int m, int n )
{
    // 基本情况
    if( m == 0 && n == 0 )
        return 0;

    if( m == 0 )
        return n;

    if( n == 0 )
        return m;

    // Recurse
    int left = EditDistanceRecursion(X, Y, m-1, n) + 1;
    int right = EditDistanceRecursion(X, Y, m, n-1) + 1;
    int corner = EditDistanceRecursion(X, Y, m-1, n-1) + (X[m-1] != Y[n-1]);

    return Minimum(left, right, corner);
}

int main()
{
    char X[] = STRING_X; // vertical
    char Y[] = STRING_Y; // horizontal

    printf("Minimum edits required to convert %s into %s is %d\n",
           X, Y, EditDistanceDP(X, Y) );
    printf("Minimum edits required to convert %s into %s is %d by recursion\n",
           X, Y, EditDistanceRecursion(X, Y, strlen(X), strlen(Y)));

    return 0;
}

以上代码转自点击打开链接

自己的代码:

<span style="font-size:18px;">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int c[1005][1005]={0};
int min(int a,int b)
{
        return (a>b)?b:a;
}
int same(char ch2,char ch1)
{
        if(ch1==ch2)
                return 0;
        else
                return 1;
}
int main()
{
    char a[1005],b[1005];
    int lena,lenb,i,j,k;
    gets(a);
    gets(b);
    lena=strlen(a);
    lenb=strlen(b);
    for(i=0;i<=lena;i++)
        c[i][0]=i;
    for(j=0;j<=lenb;j++)
        c[0][j]=j;
    for(i=1;i<=lena;i++)
    {
            for(j=1;j<=lenb;j++)
            {
                    c[i][j]=min(c[i-1][j-1]+<span style="color:#ff0000;">same(a[i-1],b[j-1])</span>,min(c[i-1][j]+1,c[i][j-1]+1));
            }
    }
    printf("%d",c[lena][lenb]);
    return 0;
}
</span>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值