1. 程式人生 > >編輯距離之動態規劃演算法

編輯距離之動態規劃演算法

在自然語言處理中,經常需要比較段落句子之間的相似度,其中廣泛使用的方法有空間向量模型、編輯距離方法。這裡,重點說一下編輯距離演算法,又叫Levenshtein距離。編輯距離的基本思想: 對於字串A, 最少經過幾次增、刪、改操作可以變為字串B, 其中操作的次數便是A和B之間的編輯距離。

如:

A:  aaabbb

B: aacb

需要把B中的c改為a,並在後面加入兩個b, 因此其編輯距離為3。

上面的操作是針對於英文字串的,對於漢字組成的句子,則需要把最小編輯單位確定為單個字。

求編輯距離可以使用動態規劃的思想。

有字串A(0...i), B(0...j)。 構建i+2行,j+2列的矩陣,對第一行依次賦值為0...j,  對第一列依次賦值為0...i。

依次對字串A的0...i和B的0...j進行比較,並填充到矩陣中,其計算公式如下:

M[i][j] = Min(M[i-1][j]+1, M[i][j-1]+1, A[i]==B[j]?M[i-1][j-1]:M[i-1][j-1]+1)

這個遞推式不難理解,既是在通過增加一個字元或修改一個字元間找到一個最小的最為當前求解問題的解。這樣就可以一步一步求解子問題,最終得出問題的解。

演算法Java程式如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * @author shao
 *
 */
public class Levenshtein {

	/**
	 * @param str1 待比較字串1
	 * @param str2 待比較字串2
	 * @return 編輯距離
	 * @description 計算編輯距離
	 */
	public static int getDistance(String str1, String str2){
		int len1 = str1.length();
		int len2 = str2.length();
		if(len1==0)
			return len2;
		else if(len2==0)
			return len1;
		
		int[][] disM = new int[len1+1][len2+1];
		for(int i=0;i<=len2;++i)
			disM[0][i] = i;
		for(int j=0;j<=len1;++j)
			disM[j][0] = j;
		for(int i=1;i<=len1;++i)
			for(int j=1;j<=len2;++j)
			{
				int top = disM[i-1][j]+1;
				int left = disM[i][j-1]+1;
				int lt = str1.charAt(i-1)==str2.charAt(j-1)?disM[i-1][j-1]:disM[i-1][j-1]+1;
				
				disM[i][j] = top<left?(top<lt?top:lt):(left<lt?left:lt);				
			}
		return disM[len1][len2];
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String str1 = null;
		String str2 = null;
		System.out.println("str1:");
		try {
			str1 = br.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("str2:");
		try {
			str2 = br.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		System.out.println(getDistance(str1,str2));
	}

}