日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[算法系列之二十六]字符串匹配之KMP算法

發(fā)布時間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [算法系列之二十六]字符串匹配之KMP算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一 簡介

KMP算法是一種改進的字符串匹配算法,由D.E.Knuth與V.R.Pratt和J.H.Morris同時發(fā)現(xiàn),因此人們稱它為克努特—莫里斯—普拉特操作(簡稱KMP算法)。KMP算法的關(guān)鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數(shù)以達到快速匹配的目的。

二 基于部分匹配表的KMP算法

舉例來說,有一個字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含搜索串”ABCDABD”?

步驟1:字符串”BBC ABCDAB ABCDABCDABDE”的第一個字符與搜索串”ABCDAB D”的第一個字符進行比較。因為字符B與A不匹配,所以搜索串后移一位。

步驟2:因為字符B與A不匹配,所以搜索串再往后移一位。

步驟3:就這樣,直到字符串有一個字符與搜索串的第一個字符相同為止。

步驟4:接著比較字符串和搜索串的下一個字符,還是相同。

步驟5:直到字符串有一個字符與搜索串對應(yīng)的字符不相同為止。

步驟6:這時,最自然的反應(yīng)是,將搜索串整體后移一位,再從頭逐個比較。這樣做雖然可行,但是效率很差,因為你要把”搜索位置”移到已經(jīng)比較過的位置,重比一遍。(這就是之前講的[算法系列之十二]字符串匹配之蠻力匹配)

步驟7:一個基本事實是,當(dāng)空格與D不匹配時,你其實知道前面六個字符是”ABCDAB”。KMP算法的想法是,充分利用這個已知信息,不要把”搜索位置”移回已經(jīng)比較過的位置,繼續(xù)把它向后移。這樣就提高了效率。

步驟8:怎么做到這一點呢?可以針對搜索串,算出一張《部分匹配表》(Partial Match Table)。這張表是如何產(chǎn)生的,后面再介紹,這里只要會用就可以了。

步驟9:已知空格與D不匹配時,前面六個字符”ABCDAB”是匹配的。

查表可知,最后一個匹配字符B對應(yīng)的”部分匹配值”為2,因此按照下面的公式算出向后移動的位數(shù):

移動位數(shù) = 已匹配的字符數(shù) - 失配字符的上一位字符對應(yīng)的部分匹配值

因為 6 - 2 等于4,所以將搜索串向后移動4位,如下圖。

步驟10:因為空格與C不匹配,搜索串還要繼續(xù)往后移。這時,已匹配的字符數(shù)為2(”AB”),對應(yīng)的”部分匹配值”為0。所以,移動位數(shù) = 2 - 0,結(jié)果為 2,于是將搜索串向后移2位。

步驟11:因為空格與A不匹配,繼續(xù)后移一位。逐位比較,直到發(fā)現(xiàn)C與D不匹配。

于是,移動位數(shù) = 6 - 2,繼續(xù)將搜索串向后移動4位。

步驟12:逐位比較,直到搜索串的最后一位,發(fā)現(xiàn)完全匹配,于是搜索完成。

如果還要繼續(xù)搜索(即找出全部匹配),移動位數(shù) = 7 - 0,再將搜索串向后移動7位,這里就不再重復(fù)了。

三 部分匹配表(Partial Match Table)

下面介紹《部分匹配表》是如何產(chǎn)生的。首先,要了解兩個概念:前綴后綴

  • 前綴指除了最后一個字符以外,一個字符串的全部頭部組合;
  • 后綴指除了第一個字符以外,一個字符串的全部尾部組合。

舉例說明:

部分匹配值就是前綴和后綴的最長的共有元素的長度

以”ABCDABD”為例。

由此得到部分匹配表,如下:

“部分匹配”的實質(zhì)是,有時候,字符串頭部和尾部會有重復(fù)。比如,”ABCDAB”之中有兩個AB,那么它的”部分匹配值”就是2(AB的長度)。搜索詞移動的時候,第一個AB向后移動4位(字符串長度-部分匹配值),就可以來到第二個AB的位置。

四 基于next數(shù)組的KMP算法

通過以上的匹配過程可以看出,問題的關(guān)鍵就是尋找搜索串中最大長度的相同前綴和后綴。找到了搜索串中每個字符之前的前綴和后綴公共部分的最大長度后,便可基于此匹配。而這個最大長度便正是next 數(shù)組要表達的含義。

4.1:根據(jù)《部分匹配表》求next 數(shù)組

經(jīng)過上面敘述我們已經(jīng)知道搜索串“ABCDABD”各個前綴后綴的最大公共元素長度了,如下圖所示:

部分匹配表也由此而出如下所示:

有了部分匹配表我們就可以利用下面公式計算移動位數(shù):

移動位數(shù) = 已匹配的字符數(shù) - 失配字符的上一位字符對應(yīng)的部分匹配值

上文利用部分匹配表和移動位數(shù)計算公式進行匹配時,我們發(fā)現(xiàn),當(dāng)一個字符失配時,其實沒必要考慮這個失配的字符,我們每次都是看的是失配字符的上一位字符“部分匹配值”。如此,便引出了next 數(shù)組。

把next 數(shù)組跟“部分匹配表”對比后,不難發(fā)現(xiàn),next 數(shù)組相當(dāng)于“部分匹配表” 整體向右移動一位,然后第一個元素值賦為-1。意識到了這一點,你會驚呼原來next 數(shù)組的求解竟然如此簡單:就是找最大對稱長度的前綴后綴,然后整體右移一位,第一個元素值賦為-1(當(dāng)然,你也可以直接計算某個字符對應(yīng)的next值,就是看這個字符之前的字符串中有多大長度的相同前綴后綴)。

更新一下搜索串移動位數(shù)的計算公式

移動位數(shù) = 失配字符的位置 - 失配字符next值

其實兩公式實質(zhì)上是一樣的,失配字符的位置等于已匹配的字符數(shù),失配字符next 值等于失配字符的上一位字符的部分匹配值,只是換一種說法而已。

4.2 遞推求解next數(shù)組

對于給定的字符串p,其next數(shù)組的含義是:對于k=next[j],p的前綴p[0…k-1]和p的后綴p[j-k…j-1]匹配,k要盡可能的大,且k< j。我們可以根據(jù)上述含義寫出next的蠻力計算方法。復(fù)雜度應(yīng)該是O(^2)。

換個思路,現(xiàn)在next[0]=-1,next[1]=0。
假設(shè)k=next[j],則p[0…k-1]=p[j-k…j-1],那么求next[j+1]有兩種情況:

  • 如果p[k] = p[j],則p[0…k]=p[j-k…j],所next[j+1]=k+1=next[j]+1
  • 如果p[k] != p[j],這是可以看做另外一個字符串匹配的問題,主串和模式串都是p,當(dāng)匹配失敗時,k應(yīng)該如何移動呢?顯然是k=next[k]
void GetNext(string T,int next[]){int size = T.size();next[0] = -1;int k = -1;int j = 0;while(j < size - 1){// p[k]表示前綴,p[j]表示后綴if(k == -1 || T[k] == T[j]){++k;++j;next[j] = k;}//ifelse{// 回溯k = next[k];}}//while}

引用:

字符串匹配的KMP算法
從頭到尾徹底理解KMP
KMP算法求next數(shù)組
KMP算法的next[]數(shù)組通俗解釋

總結(jié)

以上是生活随笔為你收集整理的[算法系列之二十六]字符串匹配之KMP算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。