KMP演算法 學習筆記

2021-08-08 20:11:35 字數 1850 閱讀 5767

—一種字串的快速匹配演算法:

舉個栗子:

找s2在s1中出現的位置:

正常的做法:先從第乙個位置開始匹配,匹配到s2的最後一位時,發現不同,這時,把s2右移一位,再從頭開始匹配,如圖:

如此匹配下去,直到:

但是,我們可以看出,前面的三次匹配都是多餘的,我們可不可以直接跳到這一步呢?

——kmp演算法

我們一開始是匹配到最後一位d和a不同,也就是說,這之前的6位都是匹配的,在這前6個字元裡,我們發現字首ab和字尾ab是相同的,也就是s2前兩位和s1的前六位的後兩位也是相同的,那麼我們可以直接跳到這裡開始往下比較,s2的第三位和s1的第七位,但是,我們怎麼知道下一步應該跳到哪個位置呢?

其實不難看出,我們往後跳的步數就是6-2=4,也就是已經匹配的串的長度減去最長的字首和字尾相等的長度

所以,我們可以預先處理s2以每一位字元結尾的串的最長的字首和字尾相等的長度(這兩個字首字尾我們在後面簡稱最長字首和最長字尾),就是kmp演算法中的next陣列

※※如何計算s2的next陣列?

對於本例中的s2,我們不難看出:每一位對應的next值為:

abcdabd

0000120

或者我們舉乙個更好理解的例子:

ababa,它的next陣列為:00123

為了容易區分我們把它複製成兩個串,比較乙個串的字首和另乙個串的字尾:

ababa

ababa

假設我們已經求出了next[4]=2,如何通過next[4]求next[5]?

設p=next[4]=2;

現在我想通過next[4]拓展next[5],那麼比較s[p+1]和s[5],發現相同,都是a,那麼next[5]=p+1;

如果不同呢?

再舉乙個例子:

在求next[10]時,發現s[5]和s[10]不相同,這時p=next[9]=4,如果相同的話,這時next[10]=p+1=5,現在不同了,next[10]的值肯定要小了,那我們往前找。

怎麼找呢?

對於next[9]的最長字首字尾abab(紅色)這個串,我們可以知道他的最長字尾和整個串的與他長度相同的字首是一樣的,也就是s[1~2]=s[8~9],如果s[3]==s[10],那麼next[10]就等於2+1=3,也就是next[p]+1,在這個例子中是成立的,所以我們的next[10]就=3了。當然,顯而易見的是,這個值不會再大了

如果在對next[p]的匹配中依然沒有匹配成功,那按照同樣的方法,讓p=next[p],繼續找下去,直到找到next[p+1]==next[10]或者p=0也就是找到頭了,停止迴圈

**體會:

void make_next()

}

有了next陣列,我們接下來的匹配就很簡單了:

其實和求next陣列的思想有一定的相似之處,如果理解了上面的**,求kmp的**就不難了:

void kmp()}}

Kmp演算法學習筆記

kmp演算法我認為難點在next陣列的建立。看kmp前我仔細看了下傳統的匹配模式,為 首元素存放串的長度 int index sstring s,sstring t else i i j 2 if j t 0 return i t 0 else return 0 我認為想深刻理解好kmp演算法要和傳...

KMP演算法學習筆記

kmp是一種字串匹配演算法,網上有許多的講解和介紹,都非常清楚明白,這裡只說明一點next i 表示 1,i 1 位中的最長公共字首字尾,因此在遇到字元不匹配時,直接將字串右移j next j 位即可。不多說了,直接上習題 poj 3461 oulipo kmp演算法裸題,直接上模板 code in...

KMP演算法學習筆記

前幾天學習了關於字串處理的kmp演算法,剛學的時候沒怎麼懂,通過今天的練題,終於把kmp掌握了。kmp演算法利用了字串的一些特殊性質,通過字首陣列,將單個字串的匹配問題由o m n 優化到了o m n 這裡,我存幾段關鍵性 首先是get next 函式 void get next 然後是kmp vo...