一: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演算法的意思,卻說不出個究竟,所謂知其然不知其所以然是也。經過七八個小時地仔細研究,終於感覺自己能說出其所以然了,又覺得資料結構書上寫得過於簡潔,不易於初學者接...