通用演算法 字串 KMP演算法

2021-10-03 10:43:05 字數 2555 閱讀 1997

kmp演算法是一種改進的字串匹配演算法。kmp演算法主要是通過消除主串指標的回溯以達到快速匹配的目的。具體實現就是生成乙個next陣列,next陣列本身包含了模式串的區域性匹配資訊。時間複雜度o(m+n)。

2.1 演算法整體流程

忽略next陣列的具體生成過程,我們先來看kmp演算法的整體流程:

文字串s和模式串p進行匹配:

假設現在文字串s匹配到 i 位置,模式串p匹配到 j 位置 ;

(1)如果j == -1,或者當前字元匹配成功(即s[i]

== p[j]),都令i++,j++;繼續匹配下乙個字元;

(2)如果j != -1,且當前字元匹配失敗(即s[i] != p[j]),則令 i 不變,j = next[j]。

如果j == s.length,則說明匹配成功,s中與p匹配的子串的起始位置為i - s.length;

否則未匹配成功。

注意,步驟(2)意味著失敗時,模式串p相對於文字串s向右移動了j - next [j] 位。 換言之,當匹配失敗時,模式串向右移動的位數為:失敗字元所在位置 - 失敗字元對應的next 值,即移動的實際位數為:j - next[j],且此值大於等於1。

2.2 next陣列的意義

上一小節我們提到了next陣列,那麼next陣列中各值的含義究竟是什麼呢?

實際上,next 陣列各值的含義是:

k=next[j],代表模式串p第j個字元之前的子串p = p[0,…,j-1]中,最開頭的k個字元和結尾的k個字元是一樣的,即p[0,…,k-1] == p[j-k,…,j-1]。

舉個例子,假設p=「abcdabd」,next[6] = 2,則表示子串p=「abcdab」中,開頭的兩個字元和結尾的兩個字元是一樣的,都是「ab」。

next陣列表示,在某個字元匹配失敗時,該字元對應位置的next 值會告訴你下一步匹配中,模式串應該跳到哪個位置(跳到next [j] 的位置)。如果next [j] 等於0或-1,則跳到模式串的開頭字元,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某個字元,而不是跳到開頭,且具體跳過了k 個字元。

繼續拿之前的例子來說,當s[10]跟p[6]匹配失敗時,kmp不是跟暴力匹配那樣簡單的把模式串右移一位,而是執行步驟(2):「如果j != -1,且當前字元匹配失敗(即s[i] != p[j]),則令 i 不變,j = next[j]」,即j 從6變到2(後面我們將求得p[6],即字元d對應的next 值為2),所以相當於模式串向右移動的位數為j - next[j](j - next[j] =6-2 = 4)。

向右移動4位後,s[10]跟p[2]繼續匹配。為什麼要向右移動4位呢,因為移動4位後,模式串中又有個「ab」可以繼續跟s[8]s[9]對應著,從而不用讓i 回溯。相當於在除去字元d的模式串子串中尋找相同的字首和字尾,然後根據字首字尾求出next 陣列,最後基於next 陣列進行匹配。

了解了next的具體含義之後,對於給定的模式串「abcdabd」,可求得它的next 陣列如下:

3、kmp演算法的**實現

(1)next的求解方法:

void

getnext

(int next[

], string p)

else

}}

(2) kmp演算法:

int

kmp(string s,string p)

else}if

(j >= plen)

else

}

(3) 改進後的 next 求解方法先來看一下上面演算法存在的缺陷:

顯然,當我們上邊的演算法得到的next陣列應該是[ -1,0,0,1 ]

所以下一步我們應該是把j移動到第1個元素咯:

不難發現,這一步是完全沒有意義的。因為後面的b已經不匹配了,那前面的b也一定是不匹配的,同樣的情況其實還發生在第2個元素a上。

顯然,發生問題的原因在於p[j] == p[next[j]]。

所以我們需要新增乙個判斷:

void

getnext

(int next[

], string p)

else

}else

}}

字串演算法 KMP演算法

給定字串m和n m比n長 找出n在m中出現的匹配位置。說白了,就是乙個簡單的字串匹配。例如 首先,字串 bbc abcdab abcdabcdabde 的第乙個字元與搜尋詞 abcdabd 的第乙個字元進行比較。因為b與a不匹配,所以搜尋詞後移一位。因為b與a不匹配,搜尋詞再往後移。就這樣,直到字串...

字串 KMP演算法

而kmp演算法在字串匹配方法中乙個很著名並且很聰明的演算法,當然也確實比較難理解。甚至於有程式設計師因為無法理解kmp演算法而直接改用暴力匹配。本身自己學演算法起步較晚,第一次接觸到kmp演算法已經是研究生畢業一年了。雖然帶著研究生的學歷背景,但是剛開始看的時候依然是一臉懵逼。看了很多博主的講解總算...

字串 KMP演算法

而kmp演算法在字串匹配方法中乙個很著名並且很聰明的演算法,當然也確實比較難理解。甚至於有程式設計師因為無法理解kmp演算法而直接改用暴力匹配。本身自己學演算法起步較晚,第一次接觸到kmp演算法已經是研究生畢業一年了。雖然帶著研究生的學歷背景,但是剛開始看的時候依然是一臉懵逼。看了很多博主的講解總算...