最近看到有人在找關於文本比較的演算法,剛好最近休假,研究了一下,終於找到一個簡單有效演算法,和大家分享一下。
演算法本身很簡單,但是要說清楚思路和原理就比較複雜了,打算分兩次發表(明天就要上班拉!),分別對應文本比較演算法中的兩個主要問題:
1。如何確定最大匹配率;
2。如何確定最優的匹配路徑;
演算法本身是基於圖論的,太麻煩了,所以不打算介紹整個思路,只將最後的結果詳細解說給大家。有問題可以發郵件給我:opensw0001@gmail.com
文本比較演算法剖析(1)-如何確定最大匹配率
1. 首先,我們假設有兩個串left和right,
left="ABCACADF"
right="BCXCADFESBABCACA"
為了直觀的分析問題,第一步,我用一個表格來逐個的比較left和right的每個元素:
圖中,1 表示left 和 right 的某個元素是匹配的,0, 就是不匹配了, 那麼, 現在的問題就是, 如何從表格中的左上方,找到一條路徑,滿足:
1. 經過的值為"1"的儲存格最多;
2. 每次只能向右,或者向下,或者向右下方移動一格;
3. 如果本次位置在值為"1"的格子上,只能向右下方移動一格;
4. 如果移動到右邊界或者下邊界外,則終止。
2 .這其實就是一個有條件搜尋最大權重路徑的問題。但是,這裡講的是文本匹配問題,和圖論相比,要簡單很多。因為文本是流式的,兩個文本之間的所有匹配關係一定是一個很規則的矩陣,這比圖論中研究的情況要簡單多了。
最先想到的是什麼呢?迭代和遞迴,是不是?別著急,沒有那麼複雜的,我們來分析一下,再做打算。
我們先用手工標出從每個匹配點出發,一直到邊界能夠經過的最多匹配點個數,如所示:
各位可以自己手工做做,分析數量有限的圖形,還是大腦比電腦好使。
3. 我們來分析一下,基本的思路是數學歸納法,呵呵,其實是遞迴演算法的數學原型。
邊界上的單元,不用說了,一定是最多隻能找到一個匹配點。
而對於表格中的任意一個單元, 我們用 N(l,r) 來表示,對於它,按照上面的規則,它有3個鄰接地區 A, B, C.
我們用N(l,r)來表示“將left的第L個元素和right的第R個元素匹配後,能夠擷取的最大匹配點數”。這個表述有點難以理解,從前面的“找到一個路徑...”的觀點出發,我們還可以這麼說明N(l,r)的含義:“從第L行R列的儲存格出發,滿足所有4個條件的路徑上能夠經過的值為"1"的單元個數”。
因為N(l,r)的下一步一定是地區A,B,C中的一個,而且,如果(l,r)是一個匹配點,只能選擇進入A地區;如果進入B,C,則(l,r)一定不是一個匹配點。因此,我們可以得到:
N(l,r) = Max( V(l,r)+N(地區A), N(地區B), N(地區C) ) 。"V(l,r)表示單元(l.r)的值,=0表示單元(l,r)不是一個匹配點,=1表示單元(l,r)是一個匹配點"
而一個地區的最大匹配點數,就是從該地區的進入點出發,所能得到的最大匹配點數,即:N(地區[(a,b),(c,d)]) = N(a,b).
"地區[(a,b),(c,d)]的意思是:由點(a,b) 和點(c,d)所構成的矩形地區)"
那麼,前式就變成了:
N(l,r) = Max( V(l.r)+N(地區A), N(地區B), N(地區C) )
= Max( N(l+1,r+1)+V(l,r) , N(l,r+1), N(l+1,r))
在excel中,我們可以驗證一下,設定儲存格L4的公式=MAX(L5,M5+B4,M4),然後拷貝這個公式直到和前面的矩陣相匹配,我們得到的結果如下:
可以和手工分析的結果對照一下(中最右部分),可以看到,結果完全一致。
Yes! 現在已經接近大功告成拉!簡單吧!現在,就是如何代碼化的問題了。
要將上面的方法編程,還差一個問題:初始化。這個很簡單,從Excel的計算結果我們就可以知道。在上面的儲存格公式中,邊界單元引用了空白單元,而我們知道excel對空白單元取值做算術運算時是按照0計算的,所以初始化為0就可以了。
再從上面的分析可以知道:
1. 迴圈應該是從右向左,從下向上的;
2. 每個儲存格的值只需要計算一次;
3. 計算N(l,r)時,需要引用3個值
因此,程式應該做逆序迴圈,用一個數組緩衝N(l+1,r)和N(l+1,r+1)的值,用一個臨時變數緩衝N(l,r+1).
假設left有M個元素;right有N個元素,那麼,這個程式的時間複雜度就是O(m.n), 空間複雜度就是Max(m,n).
好了,關於如何計算left和right的最大匹配數,就結束了。很簡單,不是嗎?
如果想做一個檔案比較工具的話,還需要確定最優的匹配路徑。這個打算在下次再說,演算法也比較簡單,不過現在已經11點多了,明天要早起嘍!
======================================