一 簡介
kmp演算法是一種改進的字串匹配演算法,由d.e.knuth與v.r.pratt和j.h.morris同時發現,因此人們稱它為克努特—莫里斯—普拉特操作(簡稱kmp演算法)。kmp演算法的關鍵是利用匹配失敗後的資訊,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。
二 基於部分匹配表的kmp演算法
舉例來說,有乙個字串」bbc abcdab abcdabcdabde」,我想知道,裡面是否包含搜尋串」abcdabd」?
步驟1:字串」bbc abcdab abcdabcdabde」的第乙個字元與搜尋串」abcdab d」的第乙個字元進行比較。因為字元b與a不匹配,所以搜尋串後移一位。
步驟2:因為字元b與a不匹配,所以搜尋串再往後移一位。
步驟3:就這樣,直到字串有乙個字元與搜尋串的第乙個字元相同為止。
步驟5:直到字串有乙個字元與搜尋串對應的字元不相同為止。
步驟6:這時,最自然的反應是,將搜尋串整體後移一位,再從頭逐個比較。這樣做雖然可行,但是效率很差,因為你要把」搜尋位置」移到已經比較過的位置,重比一遍。(這就是之前講的[演算法系列之十二]字串匹配之蠻力匹配)
步驟8:怎麼做到這一點呢?可以針對搜尋串,算出一張《部分匹配表》(partial match table)。這張表是如何產生的,後面再介紹,這裡只要會用就可以了。
步驟9:已知空格與d不匹配時,前面六個字元」abcdab」是匹配的。
查表可知,最後乙個匹配字元b對應的」部分匹配值」為2,因此按照下面的公式算出向後移動的位數:
移動位數 = 已匹配的字元數 - 失配字元的上一位字元對應的部分匹配值
因為 6 - 2 等於4,所以將搜尋串向後移動4位,如下圖。
步驟11:因為空格與a不匹配,繼續後移一位。逐位比較,直到發現c與d不匹配。
於是,移動位數 = 6 - 2,繼續將搜尋串向後移動4位。
步驟12:逐位比較,直到搜尋串的最後一位,發現完全匹配,於是搜尋完成。
三 部分匹配表(partial match table)
下面介紹《部分匹配表》是如何產生的。首先,要了解兩個概念:字首和字尾。
部分匹配值就是字首和字尾的最長的共有元素的長度。
以」abcdabd」為例。
由此得到部分匹配表,如下:
「部分匹配」的實質是,有時候,字串頭部和尾部會有重複。比如,」abcdab」之中有兩個ab,那麼它的」部分匹配值」就是2(ab的長度)。搜尋詞移動的時候,第乙個ab向後移動4位(字串長度-部分匹配值),就可以來到第二個ab的位置。
四 基於next陣列的kmp演算法
通過以上的匹配過程可以看出,問題的關鍵就是尋找搜尋串中最大長度的相同字首和字尾。找到了搜尋串中每個字元之前的字首和字尾公共部分的最大長度後,便可基於此匹配。而這個最大長度便正是next 陣列要表達的含義。
4.1:根據《部分匹配表》求next 陣列
經過上面敘述我們已經知道搜尋串「abcdabd」各個字首字尾的最大公共元素長度了,如下圖所示:
部分匹配表也由此而出如下所示:
有了部分匹配表我們就可以利用下面公式計算移動位數:
移動位數 = 已匹配的字元數 - 失配字元的上一位字元對應的部分匹配值
上文利用部分匹配表和移動位數計算公式進行匹配時,我們發現,當乙個字元失配時,其實沒必要考慮這個失配的字元,我們每次都是看的是失配字元的上一位字元「部分匹配值」。如此,便引出了next 陣列。
把next 陣列跟「部分匹配表」對比後,不難發現,next 陣列相當於「部分匹配表」 整體向右移動一位,然後第乙個元素值賦為-1。意識到了這一點,你會驚呼原來next 陣列的求解竟然如此簡單:就是找最大對稱長度的字首字尾,然後整體右移一位,第乙個元素值賦為-1(當然,你也可以直接計算某個字元對應的next值,就是看這個字元之前的字串中有多大長度的相同字首字尾)。
更新一下搜尋串移動位數的計算公式:
移動位數 = 失配字元的位置 - 失配字元next值
其實兩公式實質上是一樣的,失配字元的位置等於已匹配的字元數,失配字元next 值等於失配字元的上一位字元的部分匹配值,只是換一種說法而已。
4.2 遞推求解next陣列
對於給定的字串p,其next陣列的含義是:對於k=next[j],p的字首p[0…k-1]和p的字尾p[j-k…j-1]匹配,k要盡可能的大,且k< j。我們可以根據上述含義寫出next的蠻力計算方法。複雜度應該是o(^2)。
換個思路,現在next[0]=-1,next[1]=0。
假設k=next[j],則p[0…k-1]=p[j-k…j-1],那麼求next[j+1]有兩種情況:
void getnext(string t,int next)//if
else
}//while
}
引用:字串匹配的kmp演算法
從頭到尾徹底理解kmp
kmp演算法求next陣列
kmp演算法的next陣列通俗解釋
演算法系列之十二 字串匹配之蠻力匹配
引言 字串匹配是資料庫開發和文字處理軟體的關鍵。幸運的是所有現代程式語言和字串庫函式,幫助我們的日常工作。不過理解他們的原理還是比較重要的。字串演算法主要可以分為幾類。字串匹配就是其中之一。當我們提到字串匹配演算法,最基本的方法就是所謂的蠻力解法,這意味著我們需要檢查每乙個文字串中的字元是否和匹配串...
演算法系列之十二 字串匹配之蠻力匹配
引言 字串匹配是資料庫開發和文字處理軟體的關鍵。幸運的是所有現代程式語言和字串庫函式,幫助我們的日常工作。不過理解他們的原理還是比較重要的。字串演算法主要可以分為幾類。字串匹配就是其中之一。當我們提到字串匹配演算法,最基本的方法就是所謂的蠻力解法,這意味著我們需要檢查每乙個文字串中的字元是否和匹配串...
二十六 python中字串支援的函式
字串支援的函式 1.upper lower capitalize 例 coding utf 8 s hellopython 返回乙個新的字串 print s.upper 全部字母大寫格式 print s.lower 全部字母小寫格式 print s.capitalize 首字母大寫格式 原字串是沒有...