字串的快速匹配kmp演算法
1,樸素的模式匹配演算法
目標串 t t0 t1 t2 t3 t4 t5 t6 t7 t8 t9……
模式串 pat p0 p1 p2 p3 p4 p5 p6 p7 p8 p9……
如果t0=p0,t1=p1,t2=p2 tm-1=pm-1,則字串匹配成功,否則將pat串後移一位
形成目標串 t t0 t1 t2 t3 t4 t5 t6 t7 t8 t9……
模式串 pat p0 p1 p2 p3 p4 p5 p6 p7 p8 p9……
再次進行匹配判斷,失敗再後移一位,如果tn-1和pm-1不相等,則匹配結束,返回不存在目標串中不含有字串
這種匹配演算法是帶回溯的演算法,一旦比較不相等,就將模式串pat後移一位,從p0開始判斷,設目標串的長度為n,匹配串的長度為m,第一趟失敗比較m次,第二趟失敗又比較m次,依次下去,最壞的情況是比較n-m+1次,在多數的情況下m是遠小於n的,所以可以認為演算法的時間複雜度是o(m*n)。由此我們引入一種不回溯的匹配演算法,提高匹配的效率。
2改進的演算法kmp演算法
我們給出目標串味t abbaba,模式串為aba
根據樸素演算法匹配為
t a b b a b a
p a b a
我們可以看到第一趟t0=p0,t1=p1,t2!=p2;但是p0!=t1;由此可以推斷t1=p1!=p0,將p右移一位用t1和p0比較是肯定不相等的,沒必要再進行了,p0=p2,所以同樣p0!=t2;這一趟也不用比較,我們應該直接將p向右移動3位,直接用t3和p0進行比較,這樣匹配就消除了回溯,這就是kmp演算法的思想
一般情況 t=「t0t1t2t3t4……tn-1」,模式p="p0p1p2p3pn-1",根據1中的樸素匹配演算法可以得到從目標串t的第s個位置ts與模式串的第0個位置進行比較,直到在目標t第s+j位置t(s+j)處失配
這是,可以得到 t(s)t(s+1)t(s+2)t(s+3)……t(s+j-1)=p0p1p2p3……p(j-1) (x)
那麼下一趟應該從目標t中第(s+1)個位置開始匹配
若想成功則有,p0p1p2p3……p(m-1)=t(s+1)t(s+2)t(s+3)………t(s+m);
如果在模式串p中p0p1p2p3……p(j-2) != p1p2p3……p(j-1); (y)
則第s+1趟不用比較了
因為由xy式可以得到 p0p1p2p3……p(j-2) !=t(s+1)t(s+2)t(s+3)……t(s+j-1)
那麼第s+2趟呢,
我們要判斷一下p0p1p2……p(j-3)與p2p3……p(j-1)的關係。
如果p0p1p2……p(j-3)!= p2p3……p(j-1)
仍有p0p1p2p3……p(j-3) != t(s+2)t(s+3)……t(s+j-1)
這一趟沒必要
我們以此類推直到有乙個k使p0p1……p(k+1) != p(j-k-2)(j-k-1)……p(j-1)
p0p1……p(k) = p(j-k-1)(j0k)……p(j-1)
才有p0p1……p(k) = t(s+j-k-1)t(s+j-k)……t(s+j-1)
p(j-k-1) p(j-k) ……p(j-1)
這時模式串p已經向後滑動了j-k-1位,因此可以直接從t中的t(s+j)與模式中的p(k+1)開始,繼續向下比較。
這個演算法中,目標t在第s趟比較失配後,指標s不必回溯,演算法下一趟從此開始向下進行比較,而在模式p中,掃瞄指標p應退回到p(k+1)處
對於不同的j值,k值只依賴與模式p本身的前j個字元的構成。因此我們可以用乙個next陣列來表示
設模式p=p0p1p2p3……pm-2pm-1,則next陣列的取值如下
-1(j=0)時
next(j) = k+1當0<=k
int fastfind(char *s,char *str,int next)//s為目標串,str為匹配串
{int p=0;
int t=-1;
int lent=strlnen(s);
int lenp=strlen(str);
while(p
時間複雜度取決於while迴圈,因為無回溯,最多比較lent次,時間複雜度為o(lent)。
那麼問題來了,我們如何得到next陣列。
我們可以用遞推的方法得到next陣列;設next(j)=k;
則0<=kp0p1……p(k=1)=p(j-k-1)p(j-k)……p(j)成立
若p(k+1)=p(j),next(j+1)=k+1=next(j)+1;
若p(k+1) != p(j),在p0p1p2……pk中存在p0p1……ph = p(k-h)p(k-h+1)……p(k);
1 存在h值
next(k)=h;
p0p1……ph = p(k-h)p(k-h+1)……p(k)
= p(j-h-1)p(j-h)……p(j-1)
如果p(h+1)=p(j)
next(j+1)=h+1=next(k)+1=next(next(j))+1;
否則在p0p1……ph中尋找更小的值,next(h)=t;以此下去,直到next(t)=-1,失敗
求next陣列**
void getnext(int next,char *str)
{int j=0;
int k=-1;
int lenp=strlen(str);
next[0]=-1;
while(j
KMP演算法的總結
1 kmp的作用 用於字串匹配,用於查詢乙個字串是否是另乙個字串的子串,可以返回出現的次數以及出現的位置。2 kmp的模板 include include include using namespace std char s1 110 char s2 110 int next 110 void ge...
KMP演算法總結
kmp題目重在理解next陣列的含義 next陣列的作用 next j 記錄模式串中第 j 個字元的最長公共字首長度 重要,這是它的意義所在 第二種理解方式,當模式串與主串失配時,跳回的位置。next len 即字串 0 結束標誌的next值 單個字串匹配時與週期有關 hdu 1711 模板題 33...
KMP演算法總結
kmp演算法是用來實現模式匹配的,其時間複雜度是o m n 具體原理見 其中有用到next陣列來計算子串中公共項的位數,簡單來說,就是子串遇到不匹配時,就查next資料來決定前進幾位 移動位數 已匹配的字元數 對應的部分匹配值 1 要不要減一看next陣列第一位是不是為1,個人覺得加一後是有好處的,...