KMP演算法的概述

2021-08-10 09:58:34 字數 2804 閱讀 9496

一:kmp演算法是乙個模式匹配演算法,他最原始的方法就是從主串進行乙個個的進行匹配,然後返回主串中模式串的第乙個字母在主串中的位置,依次進行返回就能查出有多少子串。然後對於有些模式串返回時會有一些無必要的比較,所以要用演算法進行優化處理,使其演算法的時間複雜度由o(n*m)簡化為o(n+m);

對於o(n*m)這個演算法只能承受10的5次方以下的題。

1:next陣列。

假設有乙個字串s(下標從0開始),那麼他的第i號位作為結尾的子串就是s【0……i】。對該子串來說,

長度為k+1的字首與字尾分別是s【0,……k】和s【i-k……i】。現在定義乙個int型陣列next,其中next表示 使子串s【0……i】的字首s【0……k】等於字尾s【i-k……i】的最大k(注意字首和字尾可以部分重疊,但不能是s【0……i】本身);如果找不到相等的字首和字尾,那麼令next【i】=-1.顯然,next【i】就是所求最長相等的前字尾中字首最後一位的下標。

舉乙個例子:對於模式串ababaab,next陣列計算過程是:

i=0時,子串s[0……i]為『a』,所以找不到相等的前字尾,所以next=-1;

i=1時,子串s【0……i】為『ab』,next=-1;

i=2時,子串s【0……i】為『aba』,所以當k=0時,s【0,k】=『a』,s【i-k,i】=『a』;k=1時,s【0,k】=『ab』,s【i-k,i】=『ba』;所以next=0;

i=3時,子串s【0……i】為『abab』,所以k=1時,s【0,k】=『ab』,s【k,i】=『ab』,所以next=1;

i=4時,子串s【0……i】為「ababa」,所以k=0時,s【0,0】=『a』,s【4,4】=『a』;k=1時,s【0,1】=『ab』,s【3,4】=『ba』,不成立;k=2時,s【0,2】=『aba』

s【2,4】=『aba』;k=3時,s【0,3】=『abab』,s【1,4】=『baba』,不成立。所以next=2;

i=5時,子串s【0……i】為『ababaa』,所以當k=3時,s【0,3】=『abab』,s【2,5】=『abaa』,不成立等等,所以next=0;

i=6時,子串s【0……i】為『ababaab』,所以當k=1時,s【0,1】=『ab』,s【5,6】=『ab』,所以next=1;

注意:next陣列中的k的值是最後一位的字首的最後乙個位置,要注意字首加字尾可能不相等。

對於這個例子,我們求解next陣列時用暴力進行計算時是非常耗時的,下面就是用遞推的方法進行計算。

作為舉例,假設我們求出next=-1,next=-1,next=0,next=1,現在求解 next。當我們已經的到next=1,最長字尾為

『ab』,由於s=『a』=s【next+1】所以next=next+1,最長字尾為『aba』;並讓j指向next;

接著在此基礎上求解next,當知道next=2時,由於s!=s【next+1】,所以不能擴充套件最長相等的前字尾。次失敗,要用別的方法

進行處理了。此時若找到乙個j使得s=s【j+1】。然後怎樣找到這個j呢,你就需要不斷的用j=next【j】進行返回只要找到就使next=j+1;

具體的實現**:

void next(char s,int len)

if(s[i]==s[j+1])

next[i]=j;//令next【i】等於j 

}}

這段**每次只求乙個next值,然後就是對於這個理解最難。對於每次求解next【i】時,總是用j指向next【i】,以方便求解next【i+1】之用。

還有乙個從1開始的**;

#include

#include

int next[25];

/*//這個next函式是用來求從1開始的next值 

void get(char t)

else

}for(int i=1;iprintf("%d",next[i]);

}}*/

//這個next函式時更簡便的求乙個函式的值

void  nextnal(char t)

else

}else

}for(int i = 1;iprintf("%d",next[i]);}}

int main()

然後就是kmp演算法:

//計算a中是否存在b 

bool kmp(char a,char b)

if(a[i]==b[j+1])

if(j==m-1)

} return false;

}

對於這個kmp演算法就發現求解next陣列就是求解kmp演算法的實現。

求解next陣列的過程其實就是模式串pattern進行自我匹配的過程。

//計算a中存在b的數量 

bool kmp(char a,char b)

if(a[i]==b[j+1])

if(j==m-1)

} return ans;

}對於求解next陣列時,有些特殊例子:如aaaab,用next陣列求就是01234,但我們發現這有些不必要的操作。所以還有更優的方法。

對於這個函式**只有最後一步與前面不同。

void next(char s,int len)

if(s[i]==s[j+1])

if(j==-1||s[i+1]!=s[j+1]) 

else}}

從**中可以看出,只是對next【i】=j做了補充而已。

二:從有限狀態自動機的角度看待kmp演算法

事實上,有限狀態自動機可以看做乙個有向圖,其中頂點表示不同的狀態,邊表示狀態之間的轉移。

演算法 KMP演算法

kmp演算法主要解決的問題就是在字串 主串 中的模式 pattern 定位問題。記主串為t,模式串為p,則kmp演算法就是返回p在t 現的具體位置,如果沒有出現則返回 1。如果 i 指標指向的字元和 j 指標指向的字元不一致,那麼把 i 右移1位,j 從0位開始,從新開始匹配 如果 i 指標指向的字...

KMP演算法詳解 適合初學KMP演算法的朋友

相信很多人 包括自己 初識kmp演算法的時候始終是丈二和尚摸不著頭腦,要麼完全不知所云,要麼看不懂書上的解釋,要麼自己覺得好像心裡了解kmp演算法的意思,卻說不出個究竟,所謂知其然不知其所以然是也。經過七八個小時地仔細研究,終於感覺自己能說出其所以然了,又覺得資料結構書上寫得過於簡潔,不易於初學者接...

KMP演算法詳解 適合初學KMP演算法的朋友

相信很多人 包括自己 初識kmp演算法的時候始終是丈二和尚摸不著頭腦,要麼完全不知所云,要麼看不懂書上的解釋,要麼自己覺得好像心裡了解kmp演算法的意思,卻說不出個究竟,所謂知其然不知其所以然是也。經過七八個小時地仔細研究,終於感覺自己能說出其所以然了,又覺得資料結構書上寫得過於簡潔,不易於初學者接...