1. 程式人生 > >演算法介紹(3) 編輯距離演算法-字串相似度

演算法介紹(3) 編輯距離演算法-字串相似度

           編輯距離,又稱Levenshtein距離,是指兩個字串之間,由一個轉成另一個所需的最少編輯操作次數。

       具體的操作方法為:
       1.修改一個字元(如把“a”替換為“b”)。
       2.增加一個字元(如把“abdd”變為“aebdd”)。
       3.刪除一個字元(如把“travelling”變為“traveling”)。


       具體演算法過程可按一下步驟進行:

       設 L(i,j)為使兩個字串和Ai和Bj相等的最小操作次數。

       當ai==bj時 顯然 L(i,j) = L(i-1,j-1)

       當ai!=bj時 

    若將它們修改為相等,則對兩個字串至少還要操作L(i-1,j-1)次
     若刪除ai或在bj後新增ai,則對兩個字串至少還要操作L(i-1,j)次
     若刪除bj或在ai後新增bj,則對兩個字串至少還要操作L(i,j-1)次
     此時L(i,j) = min( L(i-1,j-1), L(i-1,j), L(i,j-1) ) + 1 

       顯然,L(i,0)=i,L(0,j)=j, 再利用上述的遞推公式,可以直接計算出L(i,j)值。


       構造編輯距離矩陣如下:

       

        由於L(i,0)=i,L(0,j)=j,所以有:


           計算L(1, 1),L(0, 1) + 1 == 2,L(1, 0) + 1 == 2,L(0, 0)  == 0 ,min(L(0, 1),L(1, 0),L(0, 0) ) + 1

==1,因此edit(1, 1) == 1。 依次類推:


          最後得矩陣如下:


           java程式碼如下所示:

           

public class MinimumEditDistanceUtil {
	
	public static double MinimumDistance(String sourceStr, String targetString)
	{
		int sourceLength = sourceStr.length();
		int targetLength = targetString.length();
		sourceStr = sourceStr.toLowerCase();
		targetString = targetString.toLowerCase();
		int editMatrix[ ][ ] = new int[sourceLength][targetLength];
		
		for(int i = 0; i < sourceLength; i++)
			editMatrix[i][0] = i;
		for(int j = 0; j < targetLength; j++)
			editMatrix[0][j] = j;
		
		editMatrix[0][0] = 0;
		
		for(int i = 1; i < sourceLength; i++)
		{
			for(int j = 1; j < targetLength; j++)
			{
				if(sourceStr.charAt(i - 1) == targetString.charAt(j - 1))
					editMatrix[i][j] = editMatrix[i - 1][j - 1];
				else 
					editMatrix[i][j] = minimumValue(editMatrix[i][j - 1], editMatrix[i - 1][j], editMatrix[i - 1][j - 1]) + 1;
			}
		}
		
		
		return editMatrix[sourceLength - 1][targetLength - 1];
	}
	
	public static int minimumValue(int a, int b, int c)
	{
		int t = a <= b? a : b;
		return t <= c? t : c;
	}

	public static double stringSimilarity(String sourceStr, String targetString)
	{
		return 1 - MinimumDistance(sourceStr, targetString) / Math.max(1, sourceStr.length() + targetString.length());
//		return 1 - MinimumDistance(sourceStr, targetString) / Math.max(sourceStr.length(), targetString.length());
	}
}