编辑距离问题

来源:互联网 发布:温州两家人 知乎 编辑:程序博客网 时间:2024/06/08 09:12

问题描述

字符串的编辑距离也被称为距Levenshtein距离(Levenshtein Distance),属于经典算法,常用方法使用递归,更好的方法是使用动态规划算法,以避免出现重叠子问题的反复计算,减少系统开销。

《编程之美》一书中3.3节中计算两个字符串的相似度,归根到底也是要求两个字符串的距离,其中问题是这样提出的:

  许多程序会大量使用字符串。对于不同的字符串,我们希望能够有办法判断其相似程序。我们定义一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为:

  •  修改一个字符(如把”a”替换为”b”);
  •  增加一个字符(如把”abdd”变为”aebdd”);
  •  删除一个字符(如把”travelling”变为”traveling”);

        比如,对于”abcdefg”和”abcdef”两个字符串来说,我们认为可以通过增加/减少一个”g”的方式来达到目的。上面的两种方案,都仅需要一 次 。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于”距离+1”的倒数。也就是说,”abcdefg”和”abcdef”的距离为1,相似度 为1/2=0.5。给定任意两个字符串,你是否能写出一个算法来计算它们的相似度呢?

      其实这个问题的关键是要求两个字符串的编辑距离。

    例如 将kitten一字转成sitting:

  • sitten (k→s)

  • sittin (e→i)
  • sitting (→g)

俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。

编辑距离问题:找出字符串的编辑距离,即把一个字符串s1最少经过多少步操作变成编程字符串s2,操作有三种,添加一个字符,删除一个字符,修改一个字符。

假定dist(str1,str2)表示字符串从str1变换到str2的编辑距离,有以下四种情况:
用null表示字符串为空的情况

  • dist(null,null)=0;
  • dist(null,str2)=strlen(str2);
  • dist(str1,null)=strlen(str1);
  • dist(str1,str2)

    假定要求解dist(str1+char1,str2+char2),分三种情况1. 如果str1+char能够直接转换成str2,这是我们只需要插入char2即可,也就是说dist(str1+char1,str2+char2)=dist(str1+char1,str2)+12. 如果str1可以直接转成str2+char2,这是我们只需要删去char1即可,也就是说,dist(str1+char1,str2+char2)=dist(str1,str2+char2)+13. 如果str1可以直接转变成str2,也分两种情况    - 如果char1等于char2,不需要任何操作,即dist(str1+char1,str2+char2)=dist(str1,str2)    - 如果char1不等于char2,把char1换成char2即可,dist(str1+char1,str2+char2)=dist(str1,str2)+1

取上面的三种情况的最小值即可。
那我们如何实现呢?设第一个字符串a的长度为m,第二个字符串b的长度为n,为了方便,我们设一个二维数组dist[n+1][m+1],dist[i][j]表示字符串a前j个字符串变化到字符串b前j个字符串的编辑距离,这里是不是有点混乱,继续往下看:
根据上面分情况分析,我们可以写出如下动态公式:

  • if (i == 0 && j == 0)edit[i][j] = 0;
  • if (i == 0 && j > 0)edit[i][j] = j;
  • if (i > 0 && j == 0)edit[i][j] = i;
  • if (i >=1 && j >= 1)
    int k = b[i] == a[j] ? 0 : 1;
    edit[i][j] = min(edit[i - 1][j]+1, edit[i][j - 1] + 1, edit[i - 1][ j - 1] + k);

比如说字符串a=”fxpimu”,b=”xwrs”;a.length()=6,b.length()=4;即m=7,n=4;定义二维数组为dist[5][7],运算结果如下

null f x p i m u null 0 1 2 3 4 5 6 x 1 1 1 2 3 4 5 w 2 2 2 2 3 4 5 r 3 3 3 3 3 4 5 s 4 4 4 4 4 4 5

所以字符串a到字符串b的最短编辑距离为5
代码如下:

#include "stdafx.h"#include<iostream>#include<vector>#include<string>using namespace std;int min(int A, int B, int C) {    if (B < A)        A = B;    if (C < A)        A = C;    return A;}int main(){    int dist[6][8];    string a = "fxpimu";    string b = "xwrs";    a = " " + a;    b = " " + b;    for (int i = 0; i <=b.size(); i++) {        for (int j = 0; j <=a.size(); j++) {            if (i == 0 && j == 0)dist[i][j] = 0;            else if (i == 0 && j > 0)dist[i][j] = j;            else if (i > 0 && j == 0)dist[i][j] = i;            else if(i>=1&&j>=1){                int k = (b[i] == a[j] ? 0 : 1);                dist[i][j] = min(dist[i - 1][j]+1, dist[i][j - 1] + 1, dist[i - 1][ j - 1] + k);            }        }    }    for (int i = 0; i < 5; i++) {        for (int j = 0; j < 7; j++) {            printf("%d ", dist[i][j]);        }        printf("\n");    }    printf("编辑距离为%d",dist[b.size()][a.size()]);     return 0;}

参考文章:http://www.cnblogs.com/jiabei521/p/3353390.html

原创粉丝点击