KMP演算法詳解

2021-07-09 20:58:20 字數 3405 閱讀 4399

說道kmp演算法,一定要先指出問題所在之處了,問題如下:

已知乙個字串a,b

想找到在字串a中b首次完整出現的位置。

聽到這個問題,首先想到的就是樸素演算法,挨個來進行匹配,然後找到對應的答案。

樸素演算法很簡單,就是挨著遍歷,但是會有很多的重複計算,演算法複雜度為o(mn)

**如下:

# 樸素演算法

defalgorithm1

(src, target):

for i in range(len(src)):

flag = true

for j in range(len(target)):

if i + j >= len(src):

return -1

if src[i + j] != target[j]:

flag = false

break

if flag:

return i

return -1

考慮如下字串,重複的計算就很多了,因為直到最後才最終匹配。

src:abbacabbacabbacd

target:abbacd

如果匹配如上兩個字串,就會出現大量的重複計算,所以才有了之後的優化演算法

kmp演算法跟樸素演算法是對樸素演算法的乙個優化,樸素演算法很簡單,但是會有大量的重複匹配,而kmp演算法就是要把重複的匹配去掉。

kmp演算法有個核心的概念,就是next陣列,該陣列記錄最長共有元素的長度。

以abcab為例,其next = [0,0,0,1,2]

說起來比較難以理解,就是部分匹配的值。

部分匹配的實質就是其實也是kmp演算法的核心思想,kmp演算法的核心思想在我看來就是減少匹配的次數,將重複的匹配次數去掉,那這個資訊該如何去掉呢?

我們使用兩個標誌位,乙個為主字串的標誌位,乙個是模式串的標誌位。

**如下:

# kmp 演算法

defalgorithm2

(src, target):

l = make_next(target)

target_length = len(target)

src_length = len(src)

src_index = 0

target_index = 0

while src_index < src_length:

while target_index < target_length:

if src_index + target_index >= src_length:

return -1

if src[src_index + target_index] == target[target_index]:

target_index += 1

elif target_index >= 1:

src_index += target_index - l[target_index - 1]

target_index = l[target_index - 1]

else:

src_index += 1

target_index = 0

if target_index == target_length:

return src_index

return -1

先不看next陣列的計算方法,直觀的來看kmp演算法的話,我們就能理解其思想了,kmp演算法雖然是2層迴圈疊加,但是本質上,src_index 和 target_index 都是只進行了單次遍歷的,所以演算法複雜度為o(m + n)

比樸素演算法的o(mn)快了很多。

了解了演算法思想就該了解next陣列的計算原理了

看如下**

# next 陣列的計算

defmake_next

(target):

l = [0] * len(target)

flag = 0

for i in range(1, len(target)):

if target[i] == target[flag]:

flag += 1

else:

flag = 0

l[i] = flag

return l

看**可能不慎明了,其實這是計算相同的前字尾來的。

以字串abcab為例,它的next陣列為[0,0,0,1,2],

其前三個字元沒有公共的前字尾,所以都是0,到了第四位,模式串有了乙個公共的前字尾,就是a然後其字元長度1,所以next[3] = 1

到了第五位,其公共的前字尾變成了ab,所以next[4] = 2

詳細列如下:

next值

模式串字首

字尾公共部分

2abcab

abca,abc,ab,a

bcab,cab,ab,aab1

abca

abc,ab,a

bca,ca,aa0

abcab,a

bc,c無

後面的就不用說了,所有的公共前字尾均為無

而公共的前字尾可以用來計算下次的src_index的偏移距離,如果模式串在匹配到src_index位置時不匹配了,可以根據之前src_index 的下次偏移的位置應該就是src_index += target_index - l[target_index - 1]

增量為模式串已經匹配的長度與next陣列的在該處值的差

其實仔細想想就可以理解該處的意義,因為l[target_index - 1]其實代表的是之前最後匹配處的公共匹配值,如果沒有匹配,那麼偏移的距離則正好應該為target_index

說的比較複雜,實際上就是有2個問題需要弄清楚

先說這個,為何要回到l[target_index - 1]的位置,其實就是因為前面所說道的前字尾的概念。

當前的位置不匹配了,但是前面的內容其實都是匹配的,而匹配的內容,剛好跟前面有重複的字首,所以,target_index 需要回到之前字首的後面的位置,也就是l[target_index - 1]的位置。

因為l[target_index - 1]的偏移位置已經變化了,所以src_index也必須進行變化,才能夠讓我們匹配的位置對應起來。

舉例來說:

假設匹配串為abcaabcaabcab,模式串為abcab,第一次匹配,在src_index = 0,target_index = 4時出現了第一次不匹配,但是abcab的l[target_index - 1] = 1,所以src_index挪移的距離就應該為3,target_index也回到了l[target_index - 1]的位置

這樣就保證了匹配總能夠保證最少,可以不進行重複匹配

KMP演算法詳解

模式匹配的kmp演算法詳解 這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來,其實理解...

KMP演算法詳解

kmp演算法即knuth morris pratt演算法,是模式匹配的一種改進演算法,因為是名字中三人同時發現的,所以稱為kmp演算法。因為偶然接觸到有關kmp的問題,所以上網查了一下next陣列和 nextval陣列的求法,卻沒有找到,只有在csdn的資料檔案裡找到了next陣列的簡單求法 根據書...

KMP演算法詳解

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