字串之KMP詳解

2021-08-16 14:35:19 字數 2513 閱讀 2395

昨晚梳理了一下kmp的過程,感覺印象深刻了不少,在此寫下部落格加深印象,同時也希望能和大家交流。

kmp這個名字**於其三個創始人名字首字母,主要用於解決字串的匹配問題。

字串的匹配問題:假設有兩個字串s和t,問串t是否出現在串s中/串t在串s中出現了多少次。(假設串s的長度為n,串t的長度為m)

常規思路:

按照我們正常的想法,肯定是用t跟s的每一位一一匹配,一旦遇到不能匹配的時候,就將正在匹配的起始位置右移乙個,即起始位置+1,然後依然與t進行一一匹配,直到匹配成功為止,否則t不出現在s中。

這樣思路的時間複雜度為o(n*m),那麼有沒有好一點的方法來解決這個問題呢,嚶,當然有,就是眾所周知的kmp了。

kmp演算法思路:

首先我們設s串(稱為主串)為s1s2s3......sn(s0不存放字元)

設t串(模式串)為t1t2t3......tm

假設我們對兩個串進行匹配,匹配到如下過程:

si和tj不匹配了,按照上面的常規思路就是將下邊(i-j+1)加上一,再一一匹配了,但是我們的kmp不這樣

舉個栗子,假設主串為abacabadaea,模式串為abad,我們先模擬一下常規思路的匹配過程:

我們可以看到,在上面的五次匹配過程中,第二次第四次匹配是完全沒有必要的,第一次匹配不成功之後直接進行第三次匹配,再進行第五次匹配即可得到結果。

也就是說,主串當前匹配的字元可以不做移動,直接將模式串右移,因為第一次匹配的時候s3和t3已經匹配成功了,而t3又與t1相等所以我們可以將s4直接與t2進行匹配,這樣就減少了不必要的匹配次數。

通俗的講,假設有主串和模式串已經匹配到下面的樣子了

要在模式串t中找乙個位置k(k由之前的匹配可知tj-k+1...tj-1==si-k+1...si-1

所以我們只需要找到乙個k,使得t1...tk-1==tj-k+1...tj-1就行,這時匹配就分別從主串的si、模式串的tk開始了

令next[j]=k,則next[j]表示模式串中第j個字元與主串中相應字元「失配」時,在模式串中需要重新和主串中該字元進行比較的字元位置。(next被稱為字首表)

所以我們可以得到模式串的定義:

當j=1時,next[j] = 0;

當1其他情況下,next[j] = 1;

求得next陣列後,就可以根據上面的分析來求解匹配情況了。

那麼,如何求得next陣列呢?

我們先看看模式串abaabcac的next陣列的情況:

首先我們可以保證next[1] = 0,假設next[i] = k,該如何求next[i+1]呢?

如果t[i] = t[k]的話,那麼next[i+1] = next[i]+1 = k+1;

如果t[i] != t[k], 就繼續判斷t[i] 是否等於 t[next[k]] 知道找到等於或next[k] = 0為止,如果找到等於,令next[i+1] = next[next[..i..]]+1,反之如果next[next[..i..]] == 0, next[i+1] =1。

即求得next陣列。

另外對求next陣列還有乙個優化問題,如主串為aaabaaaaab,模式串為aaaab,那模式串的next陣列如下:

其實按照之前對next陣列的定義,next[2] = 1,next[3] = 2, next[4] = 3, next[5] = 4,但是因為t[next[j]] == t[j],就沒有與s[i]比較的必要了,所以可以一直往前找next[j]。

以上是我對kmp的理解,如有理解不當之處,歡迎指出。

//去吃個飯,吃完飯給出**

參考**:

#include#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define mem(a,b) memset(a,b,sizeof(a))

const int maxm = 1e4+10;

const int maxn = 1e6+10;

int n,m;

char s[maxn];

char t[maxm];

int next[maxm];

//求字首表(next陣列)

void getnext()

else

j = next[j];

}// for( int i = 0; i < m; i++)

// printf("%d ",next[i]);

// puts("");

}//求模式串在主串中出現的次數

int kmpcount()

else

j = next[j];

if( j == m)

}return ans;

}int main()

return 0;

}

字串匹配之kmp

kmp主要就是計算字首函式e q max return m void kmp char s,char p int n strlen s int m prefixcomp p,e int k 0 for int i 1 i n i putchar n 習題 試說明如何通過檢查字串pt的字首函式e,來確...

字串 之 KMP演算法

kmp演算法是一種改進的字串匹配演算法,由d.e.knuth與v.r.pratt和j.h.morris同時發現,因此人們稱它為克努特 莫里斯 普拉特操作 簡稱kmp演算法 在介紹kmp演算法之前,先介紹一下bf演算法。一.bf演算法 bf演算法是普通的模式匹配演算法,bf演算法的思想就是將目標串s的...

字串之KMP演算法

kmp演算法全稱knuth morris pratt演算法,是一種字串匹配演算法,常規字元匹配是每次移動一位,複雜度o mn 而kmp演算法複雜度o m n kmp演算法利用的是目標字串 要匹配的字串,如下圖第二行 前字尾有相同的子字串和在匹配過程中前i 1個字元已經匹配過的規律。匹配過程 部分匹配...