編輯距離算法詳解: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;
        }
    }
複製代碼
相關文章
相關標籤/搜索