字串匹配 KMP演算法詳解

2021-12-29 21:42:17 字數 2958 閱讀 2023

1 字串匹配

字串匹配是計算機的基本任務之一。

字串匹配是什麼?舉例來說,有乙個字串"bbc abcdab abcdabcdabde",我想知道,裡面是否包含另乙個字串"abcdabd"?

許多演算法可以完成這個任務,knuth-morris-pratt演算法(簡稱kmp)是最常用的之一。

2 kmp演算法

這個演算法不太容易理解,網上有很多解釋,但讀起來都很費勁。直到讀到jake boxer的文章,我才真正理解這種演算法。下面,我用自己的語言,試圖寫一篇比較好懂的kmp演算法解釋。

首先,字串"bbc abcdab abcdabcdabde"的第乙個字元與搜尋詞"abcdabd"的第乙個字元,進行比較。因為b與a不匹配,所以搜尋詞後移一位。

因為b與a不匹配,搜尋詞再往後移。

就這樣,直到字串有乙個字元,與搜尋詞的第乙個字元相同為止。

接著比較字串和搜尋詞的下乙個字元,還是相同。

直到字串有乙個字元,與搜尋詞對應的字元不相同為止。

這時,最自然的反應是,將搜尋詞整個後移一位,再從頭逐個比較。這樣做雖然可行,但是效率很差,因為你要把"搜尋位置"移到已經比較過的位置,重比一遍。

乙個基本事實是,當空格與d不匹配時,你其實知道前面六個字元是"abcdab"。kmp演算法的想法是,設法利用這個已知資訊,不要把"搜尋位置"移回已經比較過的位置,繼續把它向後移,這樣就提高了效率。

怎麼做到這一點呢?可以針對搜尋詞,算出一張《部分匹配表》(partial match table)。這張表是如何產生的,後面再介紹,這裡只要會用就可以了。

已知空格與d不匹配時,前面六個字元"abcdab"是匹配的。查表可知,最後乙個匹配字元b對應的"部分匹配值"為2,因此按照下面的公式算出向後移動的位數:

移動位數 = 已匹配的字元數 - 對應的部分匹配值

因為 6 - 2 等於4,所以將搜尋詞向後移動4位。

10.因為空格與c不匹配,搜尋詞還要繼續往後移。這時,已匹配的字元數為2("ab"),對應的"部分匹配值"為0。所以,移動位數 = 2 - 0,結果為 2,於是將搜尋詞向後移2位。

11.因為空格與a不匹配,繼續後移一位。

12.逐位比較,直到發現c與d不匹配。於是,移動位數 = 6 - 2,繼續將搜尋詞向後移動4位。

13.逐位比較,直到搜尋詞的最後一位,發現完全匹配,於是搜尋完成。如果還要繼續搜尋(即找出全部匹配),移動位數 = 7 - 0,再將搜尋詞向後移動7位,這裡就不再重複了。

14.下面介紹《部分匹配表》是如何產生的。

首先,要了解兩個概念:"字首"和"字尾"。 "字首"指除了最後乙個字元以外,乙個字串的全部頭部組合;"字尾"指除了第乙個字元以外,乙個字串的全部尾部組合。

15."部分匹配值"就是"字首"和"字尾"的最長的共有元素的長度。以"abcdabd"為例,

- "a"的字首和字尾都為空集,共有元素的長度為0;

- "ab"的字首為[a],字尾為[b],共有元素的長度為0;

- "abc"的字首為[a, ab],字尾為[bc, c],共有元素的長度0;

- "abcd"的字首為[a, ab, abc],字尾為[bcd, cd, d],共有元素的長度為0;

- "abcda"的字首為[a, ab, abc, abcd],字尾為[bcda, cda, da, a],共有元素為"a",長度為1;

- "abcdab"的字首為[a, ab, abc, abcd, abcda],字尾為[bcdab, cdab, dab, ab, b],共有元素為"ab",長度為2;

- "abcdabd"的字首為[a, ab, abc, abcd, abcda, abcdab],字尾為[bcdabd, cdabd, dabd, abd, bd, d],共有元素的長度為0。

16."部分匹配"的實質是,有時候,字串頭部和尾部會有重複。比如,"abcdab"之中有兩個"ab",那麼它的"部分匹配值"就是2("ab"的長度)。搜尋詞移動的時候,第乙個"ab"向後移動4位(字串長度-部分匹配值),就可以來到第二個"ab"的位置。

演算法時間複雜度為o(m+n)(其中m為字元段長度,n為匹配模式的長度)。

void getnext(const std::string &p, std::vector &next)

else

}}int kmp(const std::string& s, const std::string& p, const int sindex = 0)

else

}return j == p.length() ? i - j: -1;

}

字串匹配演算法 KMP詳解

這兩天在看字串匹配演算法,第一次看到kmp演算法的時候覺得很難。於是上網搜分析,網上講kmp的演算法很多,只是好像很多都講的雲裡霧裡的,不甚清晰。後來想想還是找教材看看,第一回看的是 演算法 第四版,其實沒看懂 於是再找來clrs看,恍然大悟,果然還是clrs 好。本文主要是梳理一下整個思路,盡自己...

字串KMP匹配演算法詳解

下面我再來舉個具體例子,並給出一具體執行程式 對於目的字串big是banananobano,要匹配的字串small是nano,的情況,下面是匹配過程,原理很簡單,只要先和big字串的第乙個字元比較,如果相同就比較下乙個字元 他們的第二個字元 如果不同就把small整體右移乙個,之後再從small的第...

字串匹配KMP演算法詳解。

一 什麼是kmp演算法 假設現在有這樣乙個問題 有乙個文字串s,和乙個模式串p,現在要判斷s中是否有和p匹配的子串,並查詢p在s中的位置,怎麼解決呢?如果用暴力匹配的思路,並假設現在文字串s匹配到 i 位置,模式串p匹配到 j 位置,則有 如果當前字元匹配成功 即s i p j 則i j 繼續匹配下...