KMP演算法筆記

2021-06-27 00:55:24 字數 3189 閱讀 4081

kmp演算法我是看july部落格學習,這裡只是做個筆記,詳細內容見july的blog:

kmp演算法的用途:有乙個文字串s和乙個模式串p,現在要查詢p在s中的位置。暴力匹配演算法需要對文字串s進行回溯,kmp演算法就是讓文字串不回退,只需要移動模式串j即可。

kmp演算法大體思想:就是當s[i]==p[j]時,我們對i++,j++;如果不相等則令j=next[j]。這裡next[j]為j字元之前的字串中有多大長度的相同字首字尾(注意字首不能包含最後乙個,同時字尾不能包含第乙個,所以aaaab的next陣列為-10123)。相當於將模式串向右移動了j-next[j]位。next陣列的求解採用的是迭代的思想,需要分p[j]是否等於p[k]兩種情況以求得next[j+1]。

時間複雜度:暴力匹配演算法的時間複雜度為o(n*m)(最差的情況). kmp演算法的時間複雜度為o(n+m), 因為match串(模式串)最多向右推動了長度就為n,而字串本身不回退。這裡n和m分別為文字串和字串的長度。next時間複雜度為o(m),可以這樣理解:迴圈中有兩個變數,j和k,而j與j-k每次都是增加的或者乙個不變,故最多迴圈2m次,時間複雜度為o(m)

next陣列求解:next[0]=-1,k=-1; next陣列通過**遞推求得,假定next[j] = k求next[j+1],先判斷p[j]是否等於p[k], 如果相等則令next[++j] =++k; 否則令k=next[k]《這個不太好理解》繼續迭代。時間複雜度為o(m). 

k=next[k];為什麼不是k--?給個例子dadcdadde, 當求e的next值時就會出錯。k=k-1的話求到的是倒數第二個d,則為next[e]=2+1=3這裡是dad明顯不對,然後再看abdabcabdabde據對稱性得k=next[k]是正確的

優化next陣列:next陣列主要針對模式串abab的情況,比如在文字串abacab中尋找,此時當p[3]與s[3]匹配失敗時,則將abab向右移動兩位,此時p[1]仍然等於b,匹配必然失敗,優化的next陣列主要解決這個問題。當p[3]=p[next[3]]時 令next[3]=next[next[3]]。看**則很好理解了。

以上則是個人理解筆記,下面給出具體**:

1:kmp演算法**

#include using namespace std;

// 獲取next陣列

void getnext(int *next, const char *p) // 已知next[j] 求next[j+1] 分p[j]是否等於p[k]兩種情況 迭代的思想

else }}

// 獲取優化next陣列

void getnextopt(int *next, const char *p) // 已知next[j] 求next[j+1] 分p[j]是否等於p[k]兩種情況 迭代的思想

else }}

// kmp 演算法

int kmpsearch(const char *p, const char*s)

else if(j == 0) // 這樣對於首字元不滿足的時候直接優化

i++;

else

} delete next; // 釋放動態申請的陣列

if(j == ptrlen)

return i - j;

else return -1; }

int main()

2:暴力匹配演算法——又被稱為樸素字串匹配演算法(***** string match)

#include using namespace std;

int violencesearch(const char *p, const char *s)

else

} if(j == ptrlen)

return i - j;

else return -1;

}int main()

3:求最大長度表演算法

也可以由最大長度表來求next陣列,通過最大長度表各項向右移動一位,然後初值賦值-1即可,但是這種方法求最大長度表所消耗的時間為o(n^2)

//  針對乙個字串獲得最大長度的相同字首字尾

int getmaxfix(const char *p, int plen)

else

} }return k;

}// 獲得最大長度表

void getmaxtable(const char *p, int *table)

}

kmp演算法的變形

即求模式串在文字串中出現的次數。這裡演算法的基本思想就是求出模式串的公共字首字尾即next[s.size()],當j==s.size()的時候讓j=next[s.size()]就可以了。就好比模式串abcdea,當結束的時候j=6,此時next[j] = 1,故讓j=1繼續去匹配,即前面有k位和字串中是相同的。

**如下:

#include #include using namespace std;

#define pmaxsize 10010

void getnext(int *inext, const string s)

else k = inext[k]; }}

int kmpalg(const string &p, const string &s)else if(j == 0)

i++;

else

j = inext[j];

if(j == p.size())

} delete inext;

return count;}/*

//freopen是被包含於c標準庫標頭檔案中的乙個函式,用於重定向輸入輸出流。

該函式可以在不改變**原貌的情況下改變輸入輸出環境,但使用時應當保證流是可靠的。

*/int main()

return 0;}/*

input:5ha

hahaha

wqnwqn

adaadadada

bababb

bababababababababb

dadaddaadaaddaaadaad

output:31

310*/

KMP演算法筆記

無聊開啟vjuge看了一眼,看到有乙個比賽是ac自動機,開啟看看順便xuexi一下子。需要 kmp複習一下感覺全忘了。附兩篇參考資料 和乙個練習題 include include include include include include include include include incl...

KMP演算法筆記

1.kmp演算法用於字串匹配。2.最直觀的字串查詢,是用兩次迴圈遍歷,演算法複雜度0 m n m為待查字串,n為需要查詢的子串。3.kmp演算法的目的為減少n維度。4.include include using namespace std void getnext const string ptr,...

KMP演算法筆記

kmp演算法是一種快速的字串匹配演算法,我們先從暴力字串匹配演算法講起看怎麼對其優化得到kmp演算法。這篇文章 1 暴力字串匹配 有如下兩個字串 a abcabbcabc 和b adfabcabccabcadbcabca 我們要在b中找到a的匹配位置,暴力匹配的做法就是 把a的第乙個元素與b的第乙個...