說起“字符串匹配”,恐怕算得上是計算機領(lǐng)域應用最多的功能之一,為了滿足這一需求,聰明的計算機科學家們發(fā)明了許多巧妙的算法。在上一篇漫畫中,我們介紹了BF算法和RK算法,沒看過的小伙伴可以先補補...
說起“字符串匹配”,恐怕算得上是計算機領(lǐng)域應用最多的功能之一,為了滿足這一需求,聰明的計算機科學家們發(fā)明了許多巧妙的算法。
在上一篇漫畫中,我們介紹了BF算法和RK算法,沒看過的小伙伴可以先補補課:
漫畫:什么是字符串匹配算法?
今天,我們來介紹一種性能大大優(yōu)化的字符串匹配算法。
BF算法是如何工作的?
正如同它的全稱BruteForce一樣,BF算法使用簡單粗暴的方式,對主串和模式串進行逐個字符的比較。
比如給定主串和模式串如下:
它們的比較過程是什么樣的呢?
第一輪,模式串和主串的第一個等長子串比較,發(fā)現(xiàn)第0位字符一致,第1位字符一致,第2位字符不一致:
第二輪,模式串向后挪動一位,和主串的第二個等長子串比較,發(fā)現(xiàn)第0位字符不一致:
第三輪,模式串繼續(xù)向后挪動一位,和主串的第三個等長子串比較,發(fā)現(xiàn)第0位字符不一致:
以此類推,一直到第N輪:
當模式串挪動到某個合適位置,逐個字符比較,發(fā)現(xiàn)每一位字符都是匹配時,比較結(jié)束:
壞字符規(guī)則
“壞字符” 是什么意思?就是指模式串和子串當中不匹配的字符。
還以上面的字符串為例,當模式串和主串的第一個等長子串比較時,子串的最后一個字符T就是壞字符:
當檢測到第一個壞字符之后,我們有必要讓模式串一位一位向后挪動和比較嗎?并不需要。
因為只有模式串與壞字符T對齊的位置也是字符T的情況下,兩者才有匹配的可能。
不難發(fā)現(xiàn),模式串的第1位字符也是T,這樣一來我們就可以對模式串做一次“乾坤大挪移”,直接把模式串當中的字符T和主串的壞字符對齊,進行下一輪的比較:
壞字符的位置越靠右,下一輪模式串的挪動跨度就可能越長,節(jié)省的比較次數(shù)也就越多。這就是BM算法從右向左檢測的好處。
接下來,我們繼續(xù)逐個字符比較,發(fā)現(xiàn)右側(cè)的G、C、G都是一致的,但主串當中的字符A,是又一個壞字符:
我們按照剛才的方式,找到模式串的第2位字符也是A,于是我們把模式串的字符A和主串中的壞字符對齊,進行下一輪比較:
接下來,我們繼續(xù)逐個字符比較,這次發(fā)現(xiàn)全部字符都是匹配的,比較公正完成:
//在模式串中,查找index下標之前的字符是否和壞字符匹配
private
static
int
findCharacter
(
String
pattern
,
char
badCharacter
,
int
index
)
{
for
(
int
i
=
index
-
1
;
i
>=
0
;
i
--){
if
(
pattern
.
charAt
(
i
)
==
badCharacter
){
return
i
;
}
}
//模式串不存在該字符,返回-1
return
-
1
;
}
public
static
int
boyerMoore
(
String
str
,
String
pattern
)
{
int
strLength
=
str
.
length
();
int
patternLength
=
pattern
.
length
();
//模式串的起始位置
int
start
=
0
;
while
(
start
<=
strLength
-
patternLength
)
{
int
i
;
//從后向前,逐個字符比較
for
(
i
=
patternLength
-
1
;
i
>=
0
;
i
--)
{
if
(
str
.
charAt
(
start
+
i
)
!=
pattern
.
charAt
(
i
))
//發(fā)現(xiàn)壞字符,跳出比較,i記錄了壞字符的位置
break
;
}
if
(
i
<
0
)
{
//匹配成功,返回第一次匹配的下標位置
return
start
;
}
//尋找壞字符在模式串中的對應
int
charIndex
=
findCharacter
(
pattern
,
str
.
charAt
(
start
+
i
),
i
);
//計算壞字符產(chǎn)生的位移
int
bcOffset
=
charIndex
>=
0
?
i
-
charIndex
:
i
+
1
;
start
+=
bcOffset
;
}
return
-
1
;
}
public
static
void
main
(
String
[]
args
)
{
String
str
=
"GTTATAGCTGGTAGCGGCGAA"
;
String
pattern
=
"GTAGCGGCG"
;
int
index
=
boyerMoore
(
str
,
pattern
);
System
.
out
.
println
(
"首次出現(xiàn)位置:"
+
index
);
}
好后綴規(guī)則
“好后綴” 又是什么意思?就是指模式串和子串當中相匹配的后綴。
讓我們看一組新的例子:
對于上面的例子,如何我們繼續(xù)使用“壞字符規(guī)則”,會有怎樣的效果呢?
從后向前比對字符,我們發(fā)現(xiàn)后面三個字符都是匹配的,到了第四個字符的時候,發(fā)現(xiàn)壞字符G:
接下來我們在模式串找到了對應的字符G,但是按照壞字符規(guī)則,模式串僅僅能夠向后挪動一位:
這時候壞字符規(guī)則顯然并沒有起到作用,為了能真正減少比較次數(shù),輪到我們的好后綴規(guī)則出場了。由于好后綴規(guī)則的實現(xiàn)細節(jié)比壞字符規(guī)則要難理解得多,所以我們這里只介紹一個大概思路:
我們回到第一輪的比較過程,發(fā)現(xiàn)主串和模式串都有共同的后綴“GCG”,這就是所謂的“好后綴”。
如果模式串其他位置也包含與“GCG”相同的片段,那么我們就可以挪動模式串,讓這個片段和好后綴對齊,進行下一輪的比較:
顯然,在這個例子中,采用好后綴規(guī)則能夠讓模式串向后移動更多位,節(jié)省了更多無謂的比較。
來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺,并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請聯(lián)系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內(nèi)容的準確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負責,僅作分享之用,文章版權(quán)及插圖屬于原作者。
Copyright?2013-2024 JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺保留所有權(quán)利
蘇公網(wǎng)安備32010402000125
蘇ICP備14051488號-3技術(shù)支持:南京博盛藍睿網(wǎng)絡(luò)科技有限公司
南京思必達教育科技有限公司版權(quán)所有 百度統(tǒng)計