字符串相似度算法 levenshtein distance 编辑距离算法

来源:互联网 发布:mac飞秋怎么改ip 编辑:程序博客网 时间:2024/04/30 00:04

参考:http://www.merriampark.com/ld.htm#WHATIS
http://en.wikipedia.org/wiki/Levenshtein_distance 
 

题目: 一个字符串可以通过增加一个字符,删除一个字符,替换一个字符得到另外一个字符串,假设,我们把从字符串A转换成字符串B,前面3种操作所执行的最少次数称为AB相似度
如   abc adc   度为 1
   ababababa babababab 度为 2
   abcd acdb 度为2

这个题目中,我们并不在乎两个字符串变得相等之后的字符是怎样的,如果第一个字符是相等的,则计算剩下的就可以了。如果两个字符串的第一个字符不相等,可以进行以下三操作:

1、一步之后,再将A[2,...,lenA]和B[1,...,lenB]变成相同的字符串
2、一步之后,再将A[1,...,lenA]和B[2,...,lenB]变成相同的字符串
3、一步之后,再将A[2,...,lenA]和B[2,...,lenB]变成相同的字符串

这样就可以有以下递归程序:

int caculateStringDistance(string firstStr, int firstBegin,int firstEnd, string secondStr, int secondBegin, int secondEnd)
{       

            if (firstBegin > firstEnd)
            {
                if (secondBegin > secondEnd)
                    return 0;
                else
                    return secondEnd - secondBegin + 1;
            }
            if (secondBegin > secondEnd)
            {
               if (firstBegin > firstEnd)
                    return 0;
               else
                  return firstEnd - firstBegin + 1;
            }
           if (firstStr[firstBegin] == secondStr[secondBegin])
           {
                return caculateStringDistance(firstStr, firstBegin + 1,
                        firstEnd, secondStr, secondBegin + 1, secondEnd);
           }
           else
           {
                int oneValue = caculateStringDistance(firstStr, firstBegin + 1,
                        firstEnd, secondStr, secondBegin + 2, secondEnd);
                int twoValue = caculateStringDistance(firstStr, firstBegin + 2,
                        firstEnd, secondStr, secondBegin + 1, secondEnd);
                int threeValue = caculateStringDistance(firstStr,
                        firstBegin + 2, firstEnd, secondStr, secondBegin + 2,secondEnd);
                return min(oneValue, twoValue, threeValue) + 1;
            }
}



字符串相似度算法可以使用 Levenshtein Distance算法(中文翻译:编辑距离算法) 这算法是由俄国科学家Levenshtein提出的。其步骤

StepDescription1Set n to be the length of s.
Set m to be the length of t.
If n = 0, return m and exit.
If m = 0, return n and exit.
Construct a matrix containing 0..m rows and 0..n columns.2Initialize the first row to 0..n.
Initialize the first column to 0..m.3Examine each character of s (i from 1 to n).4Examine each character of t (j from 1 to m).5If s[i] equals t[j], the cost is 0.
If s[i] doesn't equal t[j], the cost is 1.6Set cell d[i,j] of the matrix equal to the minimum of:
a. The cell immediately above plus 1: d[i-1,j] + 1.
b. The cell immediately to the left plus 1: d[i,j-1] + 1.
c. The cell diagonally above and to the left plus the cost: d[i-1,j-1] + cost.7After the iteration steps (3, 4, 5, 6) are complete, the distance is found in cell d[n,m].



    * Java
    * C++
    * Visual Basic
    * Python

Java代码 复制代码
  1. Java   
  2.   
  3. public class Distance {   
  4.   
  5.   //****************************   
  6.   // Get minimum of three values   
  7.   //****************************   
  8.   
  9.   private int Minimum (int a, int b, int c) {   
  10.   int mi;   
  11.   
  12.     mi = a;   
  13.     if (b < mi) {   
  14.       mi = b;   
  15.     }   
  16.     if (c < mi) {   
  17.       mi = c;   
  18.     }   
  19.     return mi;   
  20.   
  21.   }   
  22.   
  23.   //*****************************   
  24.   // Compute Levenshtein distance   
  25.   //*****************************   
  26.   
  27.   public int LD (String s, String t) {   
  28.   int d[][]; // matrix   
  29.   int n; // length of s   
  30.   int m; // length of t   
  31.   int i; // iterates through s   
  32.   int j; // iterates through t   
  33.   char s_i; // ith character of s   
  34.   char t_j; // jth character of t   
  35.   int cost; // cost   
  36.   
  37.     // Step 1   
  38.   
  39.     n = s.length ();   
  40.     m = t.length ();   
  41.     if (n == 0) {   
  42.       return m;   
  43.     }   
  44.     if (m == 0) {   
  45.       return n;   
  46.     }   
  47.     d = new int[n+1][m+1];   
  48.   
  49.     // Step 2   
  50.   
  51.     for (i = 0; i <= n; i++) {   
  52.       d[i][0] = i;   
  53.     }   
  54.   
  55.     for (j = 0; j <= m; j++) {   
  56.       d[0][j] = j;   
  57.     }   
  58.   
  59.     // Step 3   
  60.   
  61.     for (i = 1; i <= n; i++) {   
  62.   
  63.       s_i = s.charAt (i - 1);   
  64.   
  65.       // Step 4   
  66.   
  67.       for (j = 1; j <= m; j++) {   
  68.   
  69.         t_j = t.charAt (j - 1);   
  70.   
  71.         // Step 5   
  72.   
  73.         if (s_i == t_j) {   
  74.           cost = 0;   
  75.         }   
  76.         else {   
  77.           cost = 1;   
  78.         }   
  79.   
  80.         // Step 6   
  81.   
  82.         d[i][j] = Minimum (d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1] + cost);   
  83.   
  84.       }   
  85.   
  86.     }   
  87.   
  88.     // Step 7   
  89.   
  90.     return d[n][m];   
  91.   
  92.   }   
  93.   
  94. }   
  95.   
  96. C++   
  97.   
  98. In C++, the size of an array must be a constant, and this code fragment causes an error at compile time:   
  99.   
  100. int sz = 5;   
  101. int arr[sz];   
  102.   
  103. This limitation makes the following C++ code slightly more complicated than it would be if the matrix could simply be declared as a two-dimensional array, with a size determined at run-time.   
  104.   
  105. In C++ it's more idiomatic to use the System Template Library's vector class, as Anders Sewerin Johansen has done in an alternative C++ implementation.   
  106.   
  107. Here is the definition of the class (distance.h):   
  108.   
  109. class Distance   
  110. {   
  111.   public:   
  112.     int LD (char const *s, char const *t);   
  113.   private:   
  114.     int Minimum (int a, int b, int c);   
  115.     int *GetCellPointer (int *pOrigin, int col, int row, int nCols);   
  116.     int GetAt (int *pOrigin, int col, int row, int nCols);   
  117.     void PutAt (int *pOrigin, int col, int row, int nCols, int x);   
  118. };    
  119.   
  120. Here is the implementation of the class (distance.cpp):   
  121.   
  122. #include "distance.h"  
  123. #include <string.h>   
  124. #include <malloc.h>   
  125.   
  126. //****************************   
  127. // Get minimum of three values   
  128. //****************************   
  129.   
  130. int Distance::Minimum (int a, int b, int c)   
  131. {   
  132. int mi;   
  133.   
  134.   mi = a;   
  135.   if (b < mi) {   
  136.     mi = b;   
  137.   }   
  138.   if (c < mi) {   
  139.     mi = c;   
  140.   }   
  141.   return mi;   
  142.   
  143. }   
  144.   
  145. //**************************************************   
  146. // Get a pointer to the specified cell of the matrix   
  147. //**************************************************    
  148.   
  149. int *Distance::GetCellPointer (int *pOrigin, int col, int row, int nCols)   
  150. {   
  151.   return pOrigin + col + (row * (nCols + 1));   
  152. }   
  153.   
  154. //*****************************************************   
  155. // Get the contents of the specified cell in the matrix    
  156. //*****************************************************   
  157.   
  158. int Distance::GetAt (int *pOrigin, int col, int row, int nCols)   
  159. {   
  160. int *pCell;   
  161.   
  162.   pCell = GetCellPointer (pOrigin, col, row, nCols);   
  163.   return *pCell;   
  164.   
  165. }   
  166.   
  167. //*******************************************************   
  168. // Fill the specified cell in the matrix with the value x   
  169. //*******************************************************   
  170.   
  171. void Distance::PutAt (int *pOrigin, int col, int row, int nCols, int x)   
  172. {   
  173. int *pCell;   
  174.   
  175.   pCell = GetCellPointer (pOrigin, col, row, nCols);   
  176.   *pCell = x;   
  177.   
  178. }   
  179.   
  180. //*****************************   
  181. // Compute Levenshtein distance   
  182. //*****************************   
  183.   
  184. int Distance::LD (char const *s, char const *t)   
  185. {   
  186. int *d; // pointer to matrix   
  187. int n; // length of s   
  188. int m; // length of t   
  189. int i; // iterates through s   
  190. int j; // iterates through t   
  191. char s_i; // ith character of s   
  192. char t_j; // jth character of t   
  193. int cost; // cost   
  194. int result; // result   
  195. int cell; // contents of target cell   
  196. int above; // contents of cell immediately above   
  197. int left; // contents of cell immediately to left   
  198. int diag; // contents of cell immediately above and to left   
  199. int sz; // number of cells in matrix   
  200.   
  201.   // Step 1    
  202.   
  203.   n = strlen (s);   
  204.   m = strlen (t);   
  205.   if (n == 0) {   
  206.     return m;   
  207.   }   
  208.   if (m == 0) {   
  209.     return n;   
  210.   }   
  211.   sz = (n+1) * (m+1) * sizeof (int);   
  212.   d = (int *) malloc (sz);   
  213.   
  214.   // Step 2   
  215.   
  216.   for (i = 0; i <= n; i++) {   
  217.     PutAt (d, i, 0, n, i);   
  218.   }   
  219.   
  220.   for (j = 0; j <= m; j++) {   
  221.     PutAt (d, 0, j, n, j);   
  222.   }   
  223.   
  224.   // Step 3   
  225.   
  226.   for (i = 1; i <= n; i++) {   
  227.   
  228.     s_i = s[i-1];   
  229.   
  230.     // Step 4   
  231.   
  232.     for (j = 1; j <= m; j++) {   
  233.   
  234.       t_j = t[j-1];   
  235.   
  236.       // Step 5   
  237.   
  238.       if (s_i == t_j) {   
  239.         cost = 0;   
  240.       }   
  241.       else {   
  242.         cost = 1;   
  243.       }   
  244.   
  245.       // Step 6    
  246.   
  247.       above = GetAt (d,i-1,j, n);   
  248.       left = GetAt (d,i, j-1, n);   
  249.       diag = GetAt (d, i-1,j-1, n);   
  250.       cell = Minimum (above + 1, left + 1, diag + cost);   
  251.       PutAt (d, i, j, n, cell);   
  252.     }   
  253.   }   
  254.   
  255.   // Step 7   
  256.   
  257.   result = GetAt (d, n, m, n);   
  258.   free (d);   
  259.   return result;   
  260.        
  261. }   
  262.   
  263. Visual Basic   
  264.   
  265. '*******************************   
  266. '*** Get minimum of three values   
  267. '*******************************   
  268.   
  269. Private Function Minimum(ByVal a As Integer, _   
  270.                          ByVal b As Integer, _   
  271.                          ByVal c As Integer) As Integer   
  272. Dim mi As Integer   
  273.                              
  274.   mi = a   
  275.   If b < mi Then   
  276.     mi = b   
  277.   End If   
  278.   If c < mi Then   
  279.     mi = c   
  280.   End If   
  281.      
  282.   Minimum = mi   
  283.                              
  284. End Function   
  285.   
  286. '********************************   
  287. '*** Compute Levenshtein Distance   
  288. '********************************   
  289.   
  290. Public Function LD(ByVal s As String, ByVal t As String) As Integer   
  291. Dim d() As Integer ' matrix   
  292. Dim m As Integer ' length of t   
  293. Dim n As Integer ' length of s   
  294. Dim i As Integer ' iterates through s   
  295. Dim j As Integer ' iterates through t   
  296. Dim s_i As String ' ith character of s   
  297. Dim t_j As String ' jth character of t   
  298. Dim cost As Integer ' cost   
  299.      
  300.   ' Step 1  
  301.      
  302.   n = Len(s)   
  303.   m = Len(t)   
  304.   If n = 0 Then   
  305.     LD = m   
  306.     Exit Function   
  307.   End If    
  308.   If m = 0 Then   
  309.     LD = n   
  310.     Exit Function   
  311.   End If    
  312.   ReDim d(0 To n, 0 To m) As Integer   
  313.      
  314.   ' Step 2  
  315.      
  316.   For i = 0 To n   
  317.     d(i, 0) = i   
  318.   Next i   
  319.      
  320.   For j = 0 To m   
  321.     d(0, j) = j   
  322.   Next j   
  323.   
  324.   ' Step 3  
  325.   
  326.   For i = 1 To n   
  327.        
  328.     s_i = Mid$(s, i, 1)   
  329.        
  330.     ' Step 4  
  331.        
  332.     For j = 1 To m   
  333.          
  334.       t_j = Mid$(t, j, 1)   
  335.          
  336.       ' Step 5  
  337.          
  338.       If s_i = t_j Then   
  339.         cost = 0  
  340.       Else   
  341.         cost = 1  
  342.       End If   
  343.          
  344.       ' Step 6  
  345.          
  346.       d(i, j) = Minimum(d(i - 1, j) + 1, d(i, j - 1) + 1, d(i - 1, j - 1) + cost)   
  347.        
  348.     Next j   
  349.        
  350.   Next i   
  351.      
  352.   ' Step 7  
  353.      
  354.   LD = d(n, m)   
  355.   Erase d   
  356.   
  357. End Function  



Python代码 复制代码
  1. #!/user/bin/env python   
  2. # -*- coding: utf-8 -*-   
  3.   
  4. class arithmetic():   
  5.        
  6.     def __init__(self):   
  7.         pass  
  8.     ''''' 【编辑距离算法】 【levenshtein distance】 【字符串相似度算法】 '''  
  9.     def levenshtein(self,first,second):   
  10.         if len(first) > len(second):   
  11.             first,second = second,first   
  12.         if len(first) == 0:   
  13.             return len(second)   
  14.         if len(second) == 0:   
  15.             return len(first)   
  16.         first_length = len(first) + 1  
  17.         second_length = len(second) + 1  
  18.         distance_matrix = [range(second_length) for x in range(first_length)]    
  19.         #print distance_matrix   
  20.         for i in range(1,first_length):   
  21.             for j in range(1,second_length):   
  22.                 deletion = distance_matrix[i-1][j] + 1  
  23.                 insertion = distance_matrix[i][j-1] + 1  
  24.                 substitution = distance_matrix[i-1][j-1]   
  25.                 if first[i-1] != second[j-1]:   
  26.                     substitution += 1  
  27.                 distance_matrix[i][j] = min(insertion,deletion,substitution)   
  28.         print distance_matrix   
  29.         return distance_matrix[first_length-1][second_length-1]   
  30.        
  31. if __name__ == "__main__":   
  32.     arith = arithmetic()   
  33.     print arith.levenshtein('GUMBOsdafsadfdsafsafsadfasfadsfasdfasdfs','GAMBOL00000000000dfasfasfdafsafasfasdfdsa'