字串 KMP演算法

2021-09-24 20:18:21 字數 2436 閱讀 1073

而kmp演算法在字串匹配方法中乙個很著名並且很聰明的演算法,當然也確實比較難理解。甚至於有程式設計師因為無法理解kmp演算法而直接改用暴力匹配。本身自己學演算法起步較晚,第一次接觸到kmp演算法已經是研究生畢業一年了。雖然帶著研究生的學歷背景,但是剛開始看的時候依然是一臉懵逼。看了很多博主的講解總算是明白了,所以在這篇部落格中記錄下來自己的理解,如果能幫助到別人也是萬分榮幸了。本篇部落格參考了孤~影~關於kmp演算法的講解。

先從暴力匹配方法感受一下字串匹配的過程。其中i表示匹配過程中主字串的位置,j表示子字串的位置。可以看出,j總是從0開始匹配,而i也是從0開始,一步一步向後移。

注意上面的演算法,是i和j同時在移動,如果遇到不匹配的,那麼i和j同時回退。這種演算法簡單粗暴好理解,但是仍然有改進的地方。

以上圖為例,想象一下是自己手動拿著p去匹配s,假如第一輪沒匹配上,那麼我們很自然想到直接從第一輪跳到第四輪,因為第二輪和第三輪的首字母a明顯就和s中的字元b、c不符。

再來幾個例子感受下這個更快速的移動過程,讓我們試著發現一些規律。

上面三個例子中移動位置其實是比較理想的,假想是我們人為去匹配多半也是這樣比劃的。那麼觀察一下紅框中的字串,其實存在一定的規律。

其實在這些情況下之所以存在比暴力演算法更快的匹配,就是因為子字串本身就包含了一定的特殊性。我們可以從上圖中看出,子字串的首和尾其實存在著重複的字串。更具一般性的,

子字串p中的,p[0] ~ p[k-1] = p[j-k] ~ p[j-1]。也就是首尾重複字串,注意也是最大的首尾重複字串。注意以下一種情況。

以上就是為了說明,假如我們遇到了第j個字元不匹配時,可以直接移動到k,而不需要比較前k-1個字元。

於是現在的重點就在於怎麼求k。

1)next陣列是什麼?

next陣列記錄了子字串遇到不匹配時要回退的位置。上述舉的例子恰好是p陣列最後乙個字元不匹配,但實際上不匹配可能出現在p的任何乙個位置。因此我們為長度為n的p字串建立乙個長度也為n的next陣列。next[j]表示,當p的第j個字元出現不匹配時,字元匹配子字串應該移動到的位置,如下圖所示。

具體來說,以"abbaabcab"為例,假設要計算next[6]。那麼對於"abbaab"來說:

頭部有: a ab abb abba abbaa(不包含最後乙個字元)

尾部有: b ab aab baab bbaab (不包含第乙個字元)

最長首尾相同字串就是ab,長度為2。那麼next[6] = 2。

2)如何求next陣列?

假設k表示當前最大首尾相同字串的頭部,j指向

結合**可能更清楚。求next陣列的**:

public

static

int getnext(string ps)

else

}return

next;

}

求得了next陣列之後,就可以寫kmp演算法了:

public

static

intkmp(string ts, string ps)

else

}if (j ==p.length)

else

}

以上就是kmp演算法的原理了,總結一下:

1)kmp演算法比暴力匹配改進的地方其實只在於當子字串本身存在著一定的首尾相同的情況時,可以直接跳到頭部字串的末端。

2)kmp演算法保證了主字串的位置i不回退,而只回退子字串的位置j,而且j不需要每次都從0開始。

字串 KMP演算法

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

字串演算法 KMP演算法

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

KMP演算法 字串匹配

kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...