编辑距离算法详解:Levenshtein Distance算法

算法基本原理:假设咱们可使用d[ i , j ]个步骤(可使用一个二维数组保存这个值),表示将串s[ 1…i ] 转换为 串t [ 1…j ]所须要的最少步骤个数,那么,在最基本的状况下,即在i等于0时,也就是说串s为空,那么对应的d[0,j] 就是 增长j个字符,使得s转化为t,在j等于0时,也就是说串t为空,那么对应的d[i,0] 就是 减小 i个字符,使得s转化为t。算法

  而后咱们考虑通常状况,加一点动态规划的想法,咱们要想获得将s[1..i]通过最少次数的增长,删除,或者替换操做就转变为t[1..j],那么咱们就必须在以前能够以最少次数的增长,删除,或者替换操做,使得如今串s和串t只须要再作一次操做或者不作就能够完成s[1..i]到t[1..j]的转换。所谓的“以前”分为下面三种状况:数组

1)咱们能够在k个操做内将 s[1…i] 转换为 t[1…j-1]spa

2)咱们能够在k个操做里面将s[1..i-1]转换为t[1..j]code

3)咱们能够在k个步骤里面将 s[1…i-1] 转换为 t [1…j-1]blog

针对第1种状况,咱们只须要在最后将 t[j] 加上s[1..i]就完成了匹配,这样总共就须要k+1个操做。ci

针对第2种状况,咱们只须要在最后将s[i]移除,而后再作这k个操做,因此总共须要k+1个操做。字符串

针对第3种状况,咱们只须要在最后将s[i]替换为 t[j],使得知足s[1..i] == t[1..j],这样总共也须要k+1个操做。而若是在第3种状况下,s[i]恰好等于t[j],那咱们就能够仅仅使用k个操做就完成这个过程。get

  最后,为了保证获得的操做次数老是最少的,咱们能够从上面三种状况中选择消耗最少的一种最为将s[1..i]转换为t[1..j]所须要的最小操做次数。string

算法基本步骤: it

(1)构造 行数为m+1 列数为 n+1 的矩阵 , 用来保存完成某个转换须要执行的操做的次数,将串s[1..n] 转换到 串t[1…m] 所须要执行的操做次数为matrix[n][m]的值;

(2)初始化matrix第一行为0到n,第一列为0到m。

Matrix[0][j]表示第1行第j-1列的值,这个值表示将串s[1…0]转换为t[1..j]所须要执行的操做的次数,很显然将一个空串转换为一个长度为j的串,只须要j次的add操做,因此matrix[0][j]的值应该是j,其余值以此类推。

(3)检查每一个从1到n的s[i]字符;

(4)检查每一个从1到m的s[i]字符;

(5)将串s和串t的每个字符进行两两比较,若是相等,则让cost为0,若是不等,则让cost为1(这个cost后面会用到);

(6)a、若是咱们能够在k个操做里面将s[1..i-1]转换为t[1..j],那么咱们就能够将s[i]移除,而后再作这k个操做,因此总共须要k+1个操做。

b、若是咱们能够在k个操做内将 s[1…i] 转换为 t[1…j-1] ,也就是说d[i,j-1]=k,那么咱们就能够将 t[j] 加上s[1..i],这样总共就须要k+1个操做。

c、若是咱们能够在k个步骤里面将 s[1…i-1] 转换为 t [1…j-1],那么咱们就能够将s[i]转换为 t[j],使得知足s[1..i] == t[1..j],这样总共也须要k+1个操做。(这里加上cost,是由于若是s[i]恰好等于t[j],那么就不须要再作替换操做,便可知足,若是不等,则须要再作一次替换操做,那么就须要k+1次操做)

由于咱们要取得最小操做的个数,因此咱们最后还须要将这三种状况的操做个数进行比较,取最小值做为d[i,j]的值;

d、而后重复执行3,4,5,6,最后的结果就在d[n,m]中;

图解:

图解过程以下:

step 1:初始化以下矩阵

step 2:从源串的第一个字符(“j”)开始,从上至下与目标串进行对比

若是两个字符相等,则在今后位置的左,上,左上三个位置中取出最小的值;若不等,则在今后位置的左,上,左上三个位置中取出最小的值再加上1;

第一次,源串第一个字符“j” 与目标串的“j”对比,左,上,左上三个位置中取出最小的值0,由于两字符相等,因此加上0;接着,依次对比“j”→“e”,“j”→“r”,“j”→“r”,,“j”→“y” 到扫描完目标串。

step 3:遍历整个源串与目标串对比:

step 4:扫描完最后一列,则最后一个为最短编辑距离:

求出编辑距离,那么两个字符串的类似度 Similarity = (Max(x,y) - Levenshtein)/Max(x,y),其中 x,y 为源串和目标串的长度。

核心代码以下:

复制代码
public class LevenshteinDistance
    {
        private static LevenshteinDistance _instance = null;
        public static LevenshteinDistance Instance
        {
            get
            {
                if (_instance == null)
                {
                    return new LevenshteinDistance();
                }
                return _instance;
            }
        }
      
        public int LowerOfThree(int first, int second, int third)
        {
            int min = first;
            if (second < min)
                min = second;
            if (third < min)
                min = third;
            return min;
        }

        public int Compare_Distance(string str1, string str2)
        {
            int[,] Matrix;
            int n = str1.Length;
            int m = str2.Length;

            int temp = 0;
            char ch1;
            char ch2;
            int i = 0;
            int j = 0;
            if (n == 0)
            {
                return m;
            }
            if (m == 0)
            {

                return n;
            }
            Matrix = new int[n + 1, m + 1];

            for (i = 0; i <= n; i++)
            {
                Matrix[i, 0] = i;
            }

            for (j = 0; j <= m; j++)
            {
                Matrix[0, j] = j;
            }

            for (i = 1; i <= n; i++)
            {
                ch1 = str1[i - 1];
                for (j = 1; j <= m; j++)
                {
                    ch2 = str2[j - 1];
                    if (ch1.Equals(ch2))
                    {
                        temp = 0;
                    }
                    else
                    {
                        temp = 1;
                    }
                    Matrix[i, j] = LowerOfThree(Matrix[i - 1, j] + 1, Matrix[i, j - 1] + 1, Matrix[i - 1, j - 1] + temp);
                }
            }
          
            return Matrix[n, m];

        }

        public decimal LevenshteinDistancePercent(string str1, string str2)
        {
            int maxLenth = str1.Length > str2.Length ? str1.Length : str2.Length;
            int val = Compare_Distance(str1, str2);
            return 1 - (decimal)val / maxLenth;
        }
    }
复制代码
相关文章
相关标签/搜索