KMP演算法理解

2021-10-05 22:41:38 字數 3393 閱讀 6237

學習了kmp演算法,對此有了一些理解,通過部落格分享,如有理解錯誤的地方,請糾正!

再說明kmp演算法前見說下它用到的一些東西。給定乙個字串如 「abcdab」,那麼它的字首就是除去最後乙個字元的所有串即「abcda,abcd, abc,ab,a」,同理,字尾是出去第乙個字元的串即「bcdab,cdab,dab,ab,a」,而在kmp演算法中我們要用到要匹配串的子串的字首字尾的最大公共長度。我們還用「abcdab」這個串舉例。

各個子串

字首字尾

最大公共長度a空

空0aba

b0abcab,a

bc,b

0abcd

abc,ab,a

bcd,cd,d

0abcda

abcd,abc,ab,abcda,cda,da,a1

abcdab

abcda,abcd,abc,ab,a

bcdab,cdab,dab,ab,a

2所以你可以用乙個陣列來記錄出各個子串的字首字尾最大公共長度ab

cdab

0000

12這裡面的思想有些類似動態規劃,我們用圖來說明下。這裡把陣列命名為arr,字元陣列為str

我們知道字串的第乙個字元的子串沒有前字尾,公共長度一定為0

所以我們從後面開始 j表示字尾與字首相同的最大公共長度,有上面的**可以看出來要想出現前字尾相同,肯定是字首的頭和字尾的尾相等。

所以這裡判斷str[j]與str[i]是否相等,結果不等,故子串「ab」沒有字首和字尾相同的的子串即

同理看子串「abc」和子串「abcd」中也是沒有相同的字首和字尾即

到了這裡我們發現arr[j] == arr[i],即子串「abcda」中的字首「a」和字尾的「b」相等,j++即

當前的最大長度是1,我們發現arr[j] == arr[i],所以很容易可以推出子串「abcdab」中的字首「ab」和字尾「ab」相等,故現在的最大長度是 j++ = 2 ,同理「abcdabc」和「abcdabcd」子串也符合當前的情況即

到這裡我們發現arr[j] != arr[i],故不能通過前面的最大長度去推該子串的最大長度,j = 4>0,所以我們要回溯到這一連續的前字尾相等的上乙個狀態,即讓 j = arr[j-1],此時j = 0故正好在字元『a』處,也正是判斷子串「abcda」是否有前字尾相同的時候,只不過這是我們看的就是「abcdabcde」中字首「a」和「e」是否相同了,結果不同。此時j = 0,沒有前字尾相等的時候故「abcdabcde」這個子串也就沒有相同的前字尾。即

附上**

void

getarr

(char

* str,

int*

* arr)

}

現在我們開始講解kmp演算法,它可以解決這樣乙個問題:有乙個文字串s,和乙個模式串p,查詢p在s中的位置中第一次出現的位置。我們用圖來說明這個演算法。變數j表示匹配到相等元素的個數,str1為總串,str2為模式串

首先判斷「c」與"a"不相等,子串向後面移動一位"b"與"a"也不相等子串繼續往後移動尋找匹配即

直到找到相等這時j++,繼續匹配下面直到遇到「d」!=「b」時

如果用暴力我們就會用把子串在整體向後移動一位,讓模式串中的第乙個字元「a」與總串的「b」進行匹配即

但是我們會發現這樣要浪費很多時間,做無用的判斷。kmp演算法的解決方案是計算最大的移動位數,減少時間。我們看上面的圖,要想再完全匹配到總串,只要找到後面總串**現與模式串首字母一樣的位置,才有可以總串之後的與模式串相匹配即

讓子串移動到這裡,這樣是不是就移動了4位,比之前移動1位的效率高很多。那麼移動的這四位是怎麼計算出來的呢?

在模式串「b」時匹配失敗,即我們可以查到「abcdab」這個串的字首字尾公共元素最大長度是2,前面已經匹配成功5個字元了,我們用匹配成功的字元-失敗的上字元的最大長度 即 5-1=4,即子串向後移動4位。可以和上面求arr模擬j=arr[j-1]即j=1 即

此時先恰好是「b」與「d」匹配失敗 j此時是1 1-0=1,即模式串向後移動一位此時j=0即

繼續依次匹配,直到出現總串與模式串相等的時候即

之後"a" == 「a」,「b」 == 「b」 …… 此時 j=6=str2的長度,說明匹配成功,返回此時str1的陣列下標即可。

int

search

(char

* str1,

char

* str2)

}free

(arr)

; arr =

null

;return-1

;}

還有一種陣列儲存是在前字尾最大值公共長度陣列的基礎上演變的即next錶即

很明顯此時表是把最大值公共長度整體移動一位,前一位補-1,這樣的好處則是在判斷要移動模式串最大位數是直接用 完成匹配數-失敗位的next中的值即可。

我們分析下kmp演算法的時間複雜度,生成陣列,時間複雜度可估算為o(m),遍歷主串可以估算為o(n),所以kmp演算法的整體時間複雜度是o(m+n),m是模式串的長度,n是主串的長度。

我們在再分析下暴力,對主串遍歷一番遇到匹配再和模式串匹配,不符合,從主串的下一位接著匹配。總體時間複雜度就是o(m*n)了!

KMP演算法理解

kmp演算法的理解著實花了不少時間,幸好網上前輩的部落格寫得都相當好,結合幾篇部落格仔細想想還是可以理解的,這裡僅做一下整理。kmp演算法概念理解看這篇部落格就夠了字串匹配的kmp演算法by阮一峰 主要的邏輯那篇部落格都有講,求出next陣列,進行簡單的加減即可完成匹配。至於求解next陣列,則是k...

kmp演算法理解

宣告 下面兩段 摘自 結構之法 演算法之道 博主july大神的部落格。這裡,我只標記和注釋一下 算是自己的學習心得吧。優化過後的next 陣列求法 void getnextval char p,int next else 求next陣列,初始時 next 0 1,這個是固定的,k為當前最新求得的最長...

KMP演算法理解

kmp演算法是對普通模式匹配演算法的一種改進演算法,這種改進演算法是d.e.knuth與v.r.pratt和j.h.morris同時發現的,因此人們稱它為kmp演算法。kmp演算法最大的特徵就是引進了跳轉表 next表 下面我們來說說kmp演算法與普通演算法的區別。這裡我們先提乙個已知條件 目標串 ...