字串匹配(KMP演算法)

2021-08-01 10:52:51 字數 2998 閱讀 8541

給定乙個目標串str和模式串ptr,要求尋找ptr第一次在str出現的位置,並返回其下標,匹配不到則返回-1。

顯然暴力演算法的時間複雜度比較高

,那麼為了簡化時間複雜度:需要

充分利用模式串ptr的性質(比如裡面部分字串的重複性,即使不存在重複字段,在比較時,實現最大的移動量)。 

考察模式串ptr: 

ababaca 


這裡我們要計算乙個長度為模式串長度(m)的轉移陣列next。next陣列的含義就是乙個字串的字首和字尾最長的相同部分的長度。字首這裡指包含第乙個字元但不包含最後乙個字元的子串,字尾指包含最後乙個字元但不包含第乙個字元的子串。比如:abcjkdabc,那麼這個陣列的最長字首和最長字尾相同必然是abc。 
cbcbc,字首和字尾最長的相同部分是cbc。
abcbc,字首和字尾不存在相同的部分。比如aaaa相同的字首和字尾最長的相同部分是aaa。對於模式串ptr,ababaca,長度是7,所以next[0],next[1],next[2],next[3],next[4],next[5],next[6]分別計算的是 
a,ab,aba,abab,ababa,ababac,ababaca的字首和字尾的最長相同部分的長度。由於a,ab,aba,abab,ababa

,ababac,ababaca的字首和字尾最長相同部分是「」,「」,「a」,「ab」,「aba」,「」,「a」,所以next陣列的值是[-1,-1,0,1,2,-1,0],這裡-1表示不存在,0表示存在長度為1,2表示存在長度為3。這是為了和**相對應。

next陣列就是說一旦在某處不匹配時(下圖位置a和b),移動ptr字串,使str的對應的最大字尾(紅色2)和ptr對應的最大字首(紅色3)對齊,然後比較a和c。

如果c和a仍不相等,那麼此時將已經匹配成功的部分看成是(紅色4)和(紅色3),設此時c的下標為k,那麼如果next[k]的值不為-1,那麼繼續將(紅色4)和(紅色3)分成如下圖的(紅色5和紅色6)和(紅色7和紅色8),再移動ptr字串使得字尾和字首的公共部分對齊,即(紅色6)和(紅色7)對齊,然後比較a和d。依此類推,直到next[k]為-1。若next[k]為-1,則直接將匹配到的str位置(這裡是a)與ptr的第一位開始往後進行匹配。

2. next陣列計算

理解了kmp演算法的基本原理,下一步就是要獲得模式串每乙個位置的最大公共長度。這個最大公共長度在演算法導論裡面被記為next陣列。

在這裡要注意一點,

next

陣列表示的是長度,下標從0開始。

假設我們現在已經求得next[0]、

next[1]、next[2]、……next[i],分別表示長度為1到i的字串的字首和字尾最大公共長度,現在要求next[i+1]。由上圖我們可以看到,如果位置i(位置c)和位置next[i](位置d)處的兩個字元相同(

下標從零開始

),則next[i+1]等於next[i]加1。如果兩個位置的字元不相同,我們可以將長度為next[i]的字串繼續分割,獲得其最大公共長度next[next[i]],然後再和位置i的字元比較。這是因為長度為next[i]字首和字尾都可以分割成上部的構造,如果位置next[next[i]]和位置i的字元相同,則next[i+1]就等於next[next[i]]加1。如果不相等,就可以繼續分割長度為next[next[i]]的字串,直到字串長度為0為止,即next值為-1為止。

3. **

空間複雜度:o (m);

時間複雜度:o (n+m);

**如下:

#include #include using namespace std;

/** @brief 計算next陣列,next陣列中儲存的值是指needle[0~i]中字首和字尾最大公共部分的長度-1

** @param[in] 模式串

* @param[out] next陣列

* @return 無

*/static void cal_next(string needle, int next)

if (needle[k+1] == needle[i]) //如果相同,

next[i] = k; }}

/** @brief kmp演算法,用pattern串去匹配目標串text

** @param[in] 目標串text

* @param[in] 模式串pattern

* @return 成功則返回第一次匹配的位置,失敗返回-1

*/static int kmp(string text, string pattern)

else if (pattern.length() == 0)

int *next = new int[pattern.length()];

//計算next陣列

cal_next(pattern,next);

int k = -1;

for (int i = 0; i < text.length(); ++i)

if (pattern[k+1] == text[i])//如果匹配成功,k+1

if (k == pattern.length()-1)//匹配成功,輸出

}delete next;

return -1;

}int strstr(string haystack, string needle)

int main()

{ string str1="aaaabbasd",str2="abbasd";

cout<

KMP演算法 字串匹配

kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...

KMP字串匹配演算法

kmp核心思想 計算模式串的next陣列,主串的索引在比較的過程中不回朔 ifndef kmp h define kmp h class kmp endif include kmp.h include include include using namespace std int kmp calcu...

KMP字串匹配演算法

在介紹kmp演算法之前,先介紹一下bf演算法。一.bf演算法 bf演算法是普通的模式匹配演算法,bf演算法的思想就是將目標串s的第乙個字元與模式串p的第乙個字元進行匹配,若相等,則繼續比較s的第二個字元和p的第二個字元 若不相等,則比較s的第二個字元和p的第乙個字元,依次比較下去,直到得出最後的匹配...