python實現演算法 kmp演算法python實現

2021-10-11 03:00:59 字數 2567 閱讀 1574

kmp演算法python實現

kmp演算法

kmp演算法用於字串的模式匹配,也就是找到模式字串在目標字串的第一次出現的位置

比如abababc

那麼bab在其位置1處,bc在其位置5處

我們首先想到的最簡單的辦法就是蠻力的乙個字元乙個字元的匹配,但那樣的時間複雜度會是o(m*n)

kmp演算法保證了時間複雜度為o(m+n)

基本原理

舉個例子:

發現x與c不同後,進行移動

a與x不同,再次移動

此時比較到了c與y,

於是下一步移動成了下面這樣

這一次的移動與前兩次的移動不同,之前每次比較到上面長字串的字元位置後,直接把模式字串的首字元與它對齊,這次並沒有,原因是這次移動之前,y與c對齊,但是y前邊的ab是與自己的字首ab一樣,於是ab並不用再比較,直接從第三個位置開始比較,如圖:

所以說kmp演算法對於這種情況就直接使用當前比較字元之前的最長相同的前字尾,然後將字首與上面的長字串對齊,繼續比較後面的字串。

這裡kmp演算法中的乙個重要點就來了,如何找到模式字串中每位字元之前的最長相同前字尾呢

這裡繼續用乙個例子舉例:

下面的數字記錄以該字元為結尾的最長前字尾相同子串的長度,先初始化為0,並且第乙個字元下的數字確認為0

然後開始比較:

a與b不同,那麼b下的數字也為0同理a與c不同,c下的數字也為0,接下來a與a對齊,如下

此時a與a相同,那麼a下面的數字為1,也就是第二排字串中當前比對的字元索引+1

接下來b與b相同,c與a不相同,那麼此時上面的字串不動,下面的字串移動到當前比對位置即c的前一位的下方的數字的位置,如圖:

移動前c的前一位是b,b下方的數字是0,所以將下面字串的第0位與之前的比對位置對其,即:

當前比對位置如箭頭所示,然後繼續向後比較,一直比到c與a:

此時c與a不相同,那麼比較下面字元的前乙個字元的下方數字的位置,如圖

也就是位置為2的地方與上面比對位置對齊:

此時c與c相同,整個字串自比對完成:

此時可能會沒有理解為什麼匹配不成功的時候要再比對其前一位字元下的數字的位置,那是因為這是要找到前乙個字元位置下的最長相同字首中的最長相同字首,就舉剛才的例子:

此時a前邊是abcab,所以要找到abcab的最長相同字首,就是ab,這時

然後再移動到ab與ab對其的位置繼續比較即可

時間複雜度

簡單來講, 找到模式字串中每位字元之前的最長相同前字尾的這個方法中,如果模式字串的長度為m,那麼上面的字串的指向是一直向前移動的,下面字串的整體也是一直向前移動的,最終移動的結果將會是長度為2m,所以比較次數也是最大為2m,時間複雜度為o(m)

kmp演算法中,運用了找到模式字串中每位字元之前的最長相同前字尾的這個方法的結果,然後使用類似的方法進行比較和移動,和上邊的解釋類似,如果這個要匹配的字串長度為n,那最長的移動舉例也超不過2n,所以總的時間複雜度為o(m+n)

具體**

這裡沒有進行傳入引數的驗證,使用時還要注意。

def same_start_end(s):

"""最長前字尾相同的字元位數"""

n = len(s) #整個字串長度

j = 0 # 字首匹配指向

i = 1 # 字尾匹配指向

result_list=[0]*n

while i < n:

if j == 0 and s[j] != s[i]: # 比較不相等並且此時比較的已經是第乙個字元了

result_list[i] = 0 # 值為0

i += 1 # 向後移動

elif s[j] != s[i] and j != 0: #比較不相等,將j值設定為j前一位的result_list中的值,為了在之前匹配到的子串中找到最長相同前字尾

j = result_list[j-1]

elif s[j] == s[i]: #相等則繼續比較

result_list[i] = j+1

j = j+1

i = i+1

return result_list

def kmp(s,p):

"""kmp演算法,s是字串,p是模式字串,返回值為匹配到的第乙個字串的第乙個字元的索引,沒匹配到返回-1"""

s_length = len(s)

p_length = len(p)

i = 0 # 指向s

j = 0 # 指向p

next = same_start_end(p)

while i < s_length:

if s[i] == p[j]: # 對應字元相同

i += 1

j += 1

if j >= p_length: # 完全匹配

return i-p_length

elif s[i] != p[j]: # 不相同

if j == 0: # 與模式比較的是模式的第乙個字元

i += 1

else: # 取模式當前字元之前最長相同前字尾的字首的後乙個字元繼續比較

j = next[j]

if i == s_length: # 沒有找到完全匹配的子串

return -1

KMP演算法(Python實現)

關於kmp演算法的原理等請參閱這篇文章 kmp演算法 c 實現 本篇文章只是對kmp用python進行了實現。1.時間複雜度分析 bf演算法的時間複雜度 在最壞的情況下,bf演算法要將目標串的每乙個字元同模式串進行比較一遍,假定目標串長度為m,模式串長度為n,總的時間複雜度為o m n 而對於kmp...

KMP演算法python實現

目錄 一 找出prefix table 二 kmp演算法實現 二 測試 三 結果 四 時間複雜度簡單匹配演算法的時間複雜度為o m n kmp匹配演算法時間複雜度為o m n 1 把要匹配的字串pattern拆成子串找出最大公共前字尾,原來的要匹配的字串列入為求最大公共前字尾的行列裡面。最大公共前字...

KMP演算法 python實現

兩個字串匹配,kmp演算法時間複雜度o m n 總體思想就是對於匹配子串,利用先驗知識盡可能的不重複匹配。對於子串,計算出當前字元之前字串中相同字元的個數,這樣在子串和字串當前字元匹配不成功時,就可以直接跳轉到之前字串相同的位置的下乙個,減少了匹配的次數。例如 abab,next陣列為 0,0,0,...