字符串匹配的KMP算法(轉(zhuǎn))

作者:阮一峰
原文鏈接:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

字符串匹配是計(jì)算機(jī)的基本任務(wù)之一沧卢。
舉例來(lái)說(shuō)花枫,有一個(gè)字符串"BBC ABCDAB ABCDABCDABDE"展鸡,我想知道壁查,里面是否包含另一個(gè)字符串"ABCDABD"篓吁?


許多算法可以完成這個(gè)任務(wù)谭溉,Knuth-Morris-Pratt算法(簡(jiǎn)稱KMP)是最常用的之一。它以三個(gè)發(fā)明者命名堤尾,起頭的那個(gè)K就是著名科學(xué)家Donald Knuth芋绸。

這種算法不太容易理解媒殉,網(wǎng)上有很多解釋,但讀起來(lái)都很費(fèi)勁摔敛。直到讀到Jake Boxer的文章廷蓉,我才真正理解這種算法。下面马昙,我用自己的語(yǔ)言桃犬,試圖寫(xiě)一篇比較好懂的KMP算法解釋。


首先行楞,字符串"BBC ABCDAB ABCDABCDABDE"的第一個(gè)字符與搜索詞"ABCDABD"的第一個(gè)字符攒暇,進(jìn)行比較。因?yàn)锽與A不匹配子房,所以搜索詞后移一位形用。


因?yàn)锽與A不匹配就轧,搜索詞再往后移。


就這樣尾序,直到字符串有一個(gè)字符钓丰,與搜索詞的第一個(gè)字符相同為止躯砰。


接著比較字符串和搜索詞的下一個(gè)字符每币,還是相同。


直到字符串有一個(gè)字符琢歇,與搜索詞對(duì)應(yīng)的字符不相同為止兰怠。


這時(shí),最自然的反應(yīng)是李茫,將搜索詞整個(gè)后移一位揭保,再?gòu)念^逐個(gè)比較。這樣做雖然可行魄宏,但是效率很差秸侣,因?yàn)槟阋?搜索位置"移到已經(jīng)比較過(guò)的位置,重比一遍宠互。


一個(gè)基本事實(shí)是味榛,當(dāng)空格與D不匹配時(shí),你其實(shí)知道前面六個(gè)字符是"ABCDAB"予跌。KMP算法的想法是搏色,設(shè)法利用這個(gè)已知信息,不要把"搜索位置"移回已經(jīng)比較過(guò)的位置券册,繼續(xù)把它向后移频轿,這樣就提高了效率。


怎么做到這一點(diǎn)呢烁焙?可以針對(duì)搜索詞航邢,算出一張《部分匹配表》(Partial Match Table)。這張表是如何產(chǎn)生的骄蝇,后面再介紹膳殷,這里只要會(huì)用就可以了。


已知空格與D不匹配時(shí)乞榨,前面六個(gè)字符"ABCDAB"是匹配的秽之。查表可知,最后一個(gè)匹配字符B對(duì)應(yīng)的"部分匹配值"為2吃既,因此按照下面的公式算出向后移動(dòng)的位數(shù):
  移動(dòng)位數(shù) = 已匹配的字符數(shù) - 對(duì)應(yīng)的部分匹配值

因?yàn)?6 - 2 等于4考榨,所以將搜索詞向后移動(dòng)4位。


因?yàn)榭崭衽cC不匹配鹦倚,搜索詞還要繼續(xù)往后移河质。這時(shí),已匹配的字符數(shù)為2("AB"),對(duì)應(yīng)的"部分匹配值"為0掀鹅。所以散休,移動(dòng)位數(shù) = 2 - 0,結(jié)果為 2乐尊,于是將搜索詞向后移2位戚丸。


因?yàn)榭崭衽cA不匹配,繼續(xù)后移一位扔嵌。


逐位比較限府,直到發(fā)現(xiàn)C與D不匹配。于是痢缎,移動(dòng)位數(shù) = 6 - 2胁勺,繼續(xù)將搜索詞向后移動(dòng)4位。


逐位比較独旷,直到搜索詞的最后一位署穗,發(fā)現(xiàn)完全匹配,于是搜索完成嵌洼。如果還要繼續(xù)搜索(即找出全部匹配)案疲,移動(dòng)位數(shù) = 7 - 0,再將搜索詞向后移動(dòng)7位咱台,這里就不再重復(fù)了络拌。


下面介紹《部分匹配表》是如何產(chǎn)生的。
首先回溺,要了解兩個(gè)概念:"前綴"和"后綴"春贸。 "前綴"指除了最后一個(gè)字符以外,一個(gè)字符串的全部頭部組合遗遵;"后綴"指除了第一個(gè)字符以外萍恕,一個(gè)字符串的全部尾部組合。


"部分匹配值"就是"前綴"和"后綴"的最長(zhǎng)的共有元素的長(zhǎng)度车要。以"ABCDABD"為例允粤,
  - "A"的前綴和后綴都為空集翼岁,共有元素的長(zhǎng)度為0类垫;
  - "AB"的前綴為[A]琅坡,后綴為[B]悉患,共有元素的長(zhǎng)度為0;
 ∮馨场- "ABC"的前綴為[A, AB]售躁,后綴為[BC, C]坞淮,共有元素的長(zhǎng)度0;
 ∨憬荨- "ABCD"的前綴為[A, AB, ABC]回窘,后綴為[BCD, CD, D],共有元素的長(zhǎng)度為0市袖;
 》戎薄- "ABCDA"的前綴為[A, AB, ABC, ABCD],后綴為[BCDA, CDA, DA, A]凌盯,共有元素為"A"付枫,長(zhǎng)度為1;
 〕墼酢- "ABCDAB"的前綴為[A, AB, ABC, ABCD, ABCDA],后綴為[BCDAB, CDAB, DAB, AB, B]二打,共有元素為"AB"县忌,長(zhǎng)度為2;
 〖绦А- "ABCDABD"的前綴為[A, AB, ABC, ABCD, ABCDA, ABCDAB]症杏,后綴為[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的長(zhǎng)度為0瑞信。


"部分匹配"的實(shí)質(zhì)是厉颤,有時(shí)候,字符串頭部和尾部會(huì)有重復(fù)凡简。比如逼友,"ABCDAB"之中有兩個(gè)"AB",那么它的"部分匹配值"就是2("AB"的長(zhǎng)度)秤涩。搜索詞移動(dòng)的時(shí)候帜乞,第一個(gè)"AB"向后移動(dòng)4位(字符串長(zhǎng)度-部分匹配值),就可以來(lái)到第二個(gè)"AB"的位置筐眷。
(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末黎烈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子匀谣,更是在濱河造成了極大的恐慌照棋,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件武翎,死亡現(xiàn)場(chǎng)離奇詭異烈炭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)后频,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門梳庆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)暖途,“玉大人,你說(shuō)我怎么就攤上這事膏执∽な郏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵更米,是天一觀的道長(zhǎng)欺栗。 經(jīng)常有香客問(wèn)我,道長(zhǎng)征峦,這世上最難降的妖魔是什么迟几? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮栏笆,結(jié)果婚禮上类腮,老公的妹妹穿的比我還像新娘。我一直安慰自己蛉加,他們只是感情好蚜枢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著针饥,像睡著了一般厂抽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丁眼,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天筷凤,我揣著相機(jī)與錄音,去河邊找鬼苞七。 笑死藐守,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的莽鸭。 我是一名探鬼主播吗伤,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼硫眨!你這毒婦竟也來(lái)了足淆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤礁阁,失蹤者是張志新(化名)和其女友劉穎巧号,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體姥闭,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丹鸿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了棚品。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靠欢。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡廊敌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出门怪,到底是詐尸還是另有隱情骡澈,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布掷空,位于F島的核電站肋殴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏坦弟。R本人自食惡果不足惜护锤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酿傍。 院中可真熱鬧烙懦,春花似錦、人聲如沸拧粪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)可霎。三九已至,卻和暖如春宴杀,著一層夾襖步出監(jiān)牢的瞬間癣朗,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工旺罢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旷余,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓扁达,卻偏偏與公主長(zhǎng)得像正卧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子跪解,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容