文本比较算法Ⅱ——Needleman/Wunsch算法
在“文本比較算法Ⅰ——LD算法”中介紹了基于編輯距離的文本比較算法——LD算法。
本文介紹基于最長(zhǎng)公共子串的文本比較算法——Needleman/Wunsch算法。
還是以實(shí)例說明:字符串A=kitten,字符串B=sitting
那他們的最長(zhǎng)公共子串為ittn(注:最長(zhǎng)公共子串不需要連續(xù)出現(xiàn),但一定是出現(xiàn)的順序一致),最長(zhǎng)公共子串長(zhǎng)度為4。
定義:
LCS(A,B)表示字符串A和字符串B的最長(zhǎng)公共子串的長(zhǎng)度。很顯然,LSC(A,B)=0表示兩個(gè)字符串沒有公共部分。
Rev(A)表示反轉(zhuǎn)字符串A
Len(A)表示字符串A的長(zhǎng)度
A+B表示連接字符串A和字符串B
?
性質(zhì):
LCS(A,A)=Len(A)
LCS(A,"")=0
LCS(A,B)=LCS(B,A)
0≤LCS(A,B)≤Min(Len(A),Len(B))
LCS(A,B)=LCS(Rev(A),Rev(B))
LCS(A+C,B+C)=LCS(A,B)+Len(C)
LCS(A+B,A+C)=Len(A)+LCS(B,C)
LCS(A,B)≥LCS(A,C)+LCS(B,C)
LCS(A+C,B)≥LCS(A,B)+LCS(B,C)
?
為了講解計(jì)算LCS(A,B),特給予以下幾個(gè)定義
A=a1a2……aN,表示A是由a1a2……aN這N個(gè)字符組成,Len(A)=N
B=b1b2……bM,表示B是由b1b2……bM這M個(gè)字符組成,Len(B)=M
定義LCS(i,j)=LCS(a1a2……ai,b1b2……bj),其中0≤i≤N,0≤j≤M
故: LCS(N,M)=LCS(A,B)
LCS(0,0)=0
LCS(0,j)=0
LCS(i,0)=0
?
對(duì)于1≤i≤N,1≤j≤M,有公式一
若ai=bj,則LCS(i,j)=LCS(i-1,j-1)+1
若ai≠bj,則LCS(i,j)=Max(LCS(i-1,j-1),LCS(i-1,j),LCS(i,j-1))
?
計(jì)算LCS(A,B)的算法有很多,下面介紹的Needleman/Wunsch算法是其中的一種。和LD算法類似,Needleman/Wunsch算法用的都是動(dòng)態(tài)規(guī)劃的思想。在Needleman/Wunsch算法中還設(shè)定了一個(gè)權(quán)值,用以區(qū)分三種操作(插入、刪除、更改)的優(yōu)先級(jí)。在下面的算法中,認(rèn)為三種操作的優(yōu)先級(jí)都一樣。故權(quán)值默認(rèn)為1。
舉例說明:A=GGATCGA,B=GAATTCAGTTA,計(jì)算LCS(A,B)
第一步:初始化LCS矩陣
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
?
第二步:利用公式一,計(jì)算矩陣的第一行
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
| 0 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
?
? 第三步:利用公式一,計(jì)算矩陣的其余各行
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 5 |
| 0 | 1 | 2 | 3 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 6 |
?
則,LCS(A,B)=LCS(7,11)=6
可以看出,Needleman/Wunsch算法實(shí)際上和LD算法是非常接近的。故他們的時(shí)間復(fù)雜度和空間復(fù)雜度也一樣。時(shí)間復(fù)雜度為O(MN),空間復(fù)雜度為O(MN)。空間復(fù)雜度經(jīng)過優(yōu)化,可以優(yōu)化到O(M),但是一旦優(yōu)化就喪失了計(jì)算匹配字串的機(jī)會(huì)了。由于代碼和LD算法幾乎一樣。這里就不再貼代碼了。
還是以上面為例A=GGATCGA,B=GAATTCAGTTA,LCS(A,B)=6
他們的匹配為:
A:GGA_TC_G__A
B:GAATTCAGTTA
如上面所示,藍(lán)色表示完全匹配,黑色表示編輯操作,_表示插入字符或者是刪除字符操作。如上面所示,藍(lán)色字符有6個(gè),表示最長(zhǎng)公共子串長(zhǎng)度為6。
利用上面的Needleman/Wunsch算法矩陣,通過回溯,能找到匹配字串
第一步:定位在矩陣的右下角
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 5 |
| 0 | 1 | 2 | 3 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 6 |
?
第二步:回溯單元格,至矩陣的左上角
若ai=bj,則回溯到左上角單元格
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 5 |
| 0 | 1 | 2 | 3 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 6 |
?
? 若ai≠bj,回溯到左上角、上邊、左邊中值最大的單元格,若有相同最大值的單元格,優(yōu)先級(jí)按照左上角、上邊、左邊的順序
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 5 |
| 0 | 1 | 2 | 3 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 6 |
?
若當(dāng)前單元格是在矩陣的第一行,則回溯至左邊的單元格
若當(dāng)前單元格是在矩陣的第一列,則回溯至上邊的單元格
?
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 4 |
| 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 5 |
| 0 | 1 | 2 | 3 | 3 | 3 | 3 | 4 | 5 | 5 | 5 | 6 |
?
依照上面的回溯法則,回溯到矩陣的左上角
第三步:根據(jù)回溯路徑,寫出匹配字串
若回溯到左上角單元格,將ai添加到匹配字串A,將bj添加到匹配字串B
若回溯到上邊單元格,將ai添加到匹配字串A,將_添加到匹配字串B
若回溯到左邊單元格,將_添加到匹配字串A,將bj添加到匹配字串B
搜索晚整個(gè)匹配路徑,匹配字串也就完成了
?
可以看出,LD算法和Needleman/Wunsch算法的回溯路徑是一樣的。這樣找到的匹配字串也是一樣的。
不過,Needleman/Wunsch算法和LD算法一樣,若要找出匹配字串,空間的復(fù)雜度就一定是O(MN),在文本比較長(zhǎng)的時(shí)候,是極為耗用存儲(chǔ)空間的。故若要計(jì)算出匹配字串,還得用其他的算法,留待后文介紹。
轉(zhuǎn)載于:https://www.cnblogs.com/jxldjsn/p/6095481.html
總結(jié)
以上是生活随笔為你收集整理的文本比较算法Ⅱ——Needleman/Wunsch算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在大城市打拼的你,是想留下还是想攒够了钱
- 下一篇: iOS蓝牙开发CoreBluetooth