KMP演算法的詳細講解

2021-09-19 16:19:08 字數 2987 閱讀 8580

kmp演算法是一種改進的字串匹配演算法。

講述kmp演算法之前,我們要先建立乙個概念,沒有這個概念,kmp很難理解。

那,我們先忘掉原問題,來進行乙個概念建設。這個概念就是:在乙個字串中,乙個字元之前的字串最長字首和最長字尾的匹配長度,有點繞,我們舉個例子吧:

對於字元d,我們想求乙個資訊,就是d之前的字串最長字首和最長字尾的匹配,同時我們要加乙個限定:字首不能包含最後乙個字元,字尾也不能包含第乙個字元,也就是說:當字首長度取1時,只有乙個字元a,字尾長度也取1時,只有字元c,a和c字元不相等,所以我們說當字首和字尾長度都取1時不相等;同理,當字首和字尾長度都取2時,即ab和bc也不相等;當字首和字尾長度都取3時相等,abc和abc,我們找到一種相等的情況,但它是最長的嗎?還得再試,當字首和字尾長度取4時,為abca和cabc,不相等;當取5時,為abcab和bcabc不相等;當取6時相等,但此時這種情況我們不能要,因為我們已經限定了:字首不能包含最後乙個字元,字尾也不能包含第乙個字元。那所有相等的可能性中,長度為3時最長。所以我們說d位置上的資訊,我想記錄的話,為3。這個3的含義就是d前面的字串最長字首和最長字尾的匹配長度。

現在,最長字首和最長字尾的概念就建立起來了

回到我們演算法本身,現在要求的是:str1包不包含str2。 我們根據str2求最長字首與最長字尾這個資訊,比如說str2為「ababac」,我們每個位置的資訊都求,也就是說我們求解的東西是個陣列,叫做

next陣列

這裡我們把求next陣列的資訊寫成乙個函式,對於0位置,在求的過程中,因為它前面沒有字串,所以預設-1,即next[0]=-1;1位置上是b,它前邊的字串只有a,而我們的概念裡又說了,字首不能包含最後乙個字元,字尾也不能包含第乙個字元,而它前邊的字串只有乙個字元,人為規定0,next[1]=0;對於2位置的資訊,因為它前邊只有兩個字元,所以它倆相等就為1,不等就為0,由於a和b不相等,此時next[2]=0;對於後面的每乙個位置都可以按照某種方法非常快的求出該字元之前的字串最長字首和最長字尾的匹配長度,求解得到完整的next陣列應為next=[-1,0,0,1,2,3], 這個方法我們後邊詳細講

然後我們先把kmp的整個過程,看看用這個資訊是怎麼加速的,完成之後再去剖析這個next陣列到底怎麼又快又對的把它解出來。

我們有這樣的資訊後,怎麼做的? 假設現在在str1中開始的位置是i位置,它和str2的0位置開始配,直到str1的x位置和str2的y位置沒配上,那之前我們一般想的解決辦法是:如果i位置往下配,如果有乙個位置沒配上,我們又從i+1位置開始再重新和str2的0位置匹配…那現在我們看看有了這個資訊之後,此時我們不把i位置回退到i+1位置再重新匹配,而現在我們關於str2的y位置求了乙個資訊(y之前最長字首和最長字尾的匹配長度),所以在str2中就有兩個相同子串(可重疊),我們將最長字尾的第乙個字元對應到str1中,假設是j位置,我們就拿str1的j位置和str2的0位置開始往下配,同時因為字尾和字首是相等的,所以等量的推過來,字首給你匹配的字元也是最長字尾的長度,即我們此時還是j位置和0位置往下配,但是因為str1的j位置到x位置之間的字元和str2的0位置和z位置之間的字元是相等的,所以我們不用再費周折進行比較,可以直接跳到str1的x位置和str2的z位置進行比較往下配,以此類推,就是這麼個流程。

我們可以看到str1的p位置 'a』字元 和 str2的q位置 『f』 字元不等,其餘都相等;

以上過程較為簡單,主要是在於如何求next陣列。

next陣列中0到2位置上的值我們已經講過, 接下來的位置用數學歸納法,在i位置上的時候,假設前邊已經正確求解了所有next陣列的值,那我想求i位置上next陣列的值,0到i位置上已經正確算過了,如果我能利用之前的結論求出i位置上最長字首與最長字尾的匹配長度,我自然可以順利的推導i+1位置上的。(:至於為什麼i位置上的資訊只需要比較i-1位置上的字元與其最長字首的下乙個字元比較,且為什麼是最長的,可以拿數學推導哦)

現在假設next陣列中 i-1位置上的資訊是4,那求i位置上的資訊就變得很簡單,只需比較i-1位置上的字元與j位置上的字元是否相等,

舉例:求最後乙個位置的next陣列資訊

注:上述說的j位置跳出來的最長前字尾長度為2,但實際算出來的不一定都是2哦

**:

public

static

intgetindexof

(string s, string m)

else

if(next[mi]==-

1)else

}return mi == ms.length ? si - mi :-1

;}public

static

int[

]getnext

(char

ms);int

next =

newint

[ms.length]

; next[0]

=-1;

next[1]

=0;int pos =2;

int cn =0;

while

(pos < next.length)

else

if(cn >0)

else

}return next;

}

kmp演算法就是這樣子的哦~~

kmp演算法講解

kmp演算法本身,解決的是判斷模板字串t,是否是字串s的子串的問題。當只需判斷子串首次出現的位置,或是否包含子串。可以用庫函式strstr s,t 代替,判斷t是否為s的子串來代替。該函式的返回值是t首次出現的位置,如果t不是s的子串則返回null。該函式的複雜度與kmp類似。kmp演算法主要分為兩...

KMP演算法講解

第一次寫部落格有點小激動,今天要講一下kmp演算法,這個查詢演算法比較難理解,我也是想了很久才想明白,我們在str2中的pos位置開始查詢str1,當找到的時候返回str2中的下標,沒有找到的時候返回 1 首先我們來參考一下我們最初寫的查詢字串的函式,定義i 0為str2的下標,j 0為str1的下...

擴充套件kmp演算法講解

參考文章 一.擴充套件kmp得到的是什麼 字串a,b。b是模式串 子串 求解a i lena 1 與b的最長公共字首,記錄在陣列ex i 中 二.演算法實現 分為兩步,第一步是對b模式串進行處理也是求b i,blen 1 與b的最長公共字首,用next陣列儲存,第二部是將a與b進行匹配,其實他們的方...