KMP演算法最淺顯理解 一看就明白

2021-08-01 09:29:28 字數 2443 閱讀 7197

kmp演算法看懂了覺得特別簡單,思路很簡單,看不懂之前,查各種資料,看的稀里糊塗,即使網上最簡單的解釋,依然看的稀里糊塗。 

我花了半天時間,爭取用最短的篇幅大致搞明白這玩意到底是啥。 

這裡不扯概念,只講演算法過程和**理解:

字串匹配。給你兩個字串,尋找其中乙個字串是否包含另乙個字串,如果包含,返回包含的起始位置。 

如下面兩個字串:

char *str = "bacbababadababacambabacaddababacasdsd";

char *ptr = "ababaca";

str有兩處包含ptr 

分別在str的下標10,26處包含ptr。

問題型別很簡單,下面直接介紹演算法

一般匹配字串時,我們從目標字串str(假設長度為n)的第乙個下標選取和ptr長度(長度為m)一樣的子字串進行比較,如果一樣,就返回開始處的下標值,不一樣,選取str下乙個下標,同樣選取長度為n的字串進行比較,直到str的末尾(實際比較時,下標移動到n-m)。這樣的時間複雜度是o(n*m)。

kmp演算法:可以實現複雜度為o(m+n)

為何簡化了時間複雜度: 

充分利用了目標字串ptr的性質(比如裡面部分字串的重複性,即使不存在重複字段,在比較時,實現最大的移動量)。

上面理不理解無所謂,我說的其實也沒有深刻剖析裡面的內部原因。

考察目標字串ptr: 

ababaca

這裡我們要計算乙個長度為m的轉移函式next。

next陣列的含義就是乙個固定字串的最長字首和最長字尾相同的長度。

比如:abcjkdabc,那麼這個陣列的最長字首和最長字尾相同必然是abc。 

cbcbc,最長字首和最長字尾相同是cbc。 

abcbc,最長字首和最長字尾相同是不存在的。

**注意最長字首:是說以第乙個字元開始,但是不包含最後乙個字元。 

比如aaaa相同的最長字首和最長字尾是aaa。** 

對於目標字串ptr,ababaca,長度是7,所以next[0],next[1],next[2],next[3],next[4],next[5],next[6]分別計算的是 

a,ab,aba,abab,ababa,ababac,ababaca的相同的最長字首和最長字尾的長度。由於a,ab,aba,abab,ababa,ababac,ababaca的相同的最長字首和最長字尾是「」,「」,「a」,「ab」,「aba」,「」,「a」,所以next陣列的值是[-1,-1,0,1,2,-1,0],這裡-1表示不存在,0表示存在長度為1,2表示存在長度為3。這是為了和**相對應。

next陣列就是說一旦在某處不匹配時(下圖綠色位置a和b),移動ptr字串,使str的對應的最大字尾(紅色2)和ptr對應的最大字首(紅色3)對齊,然後比較a和c。

next陣列的值,就是下次往前移動字串ptr的移動距離。

比如next中某個字元對應的值是4,則在該字元後的下乙個字元不匹配時,可以直接移動往前移動ptr 5個長度,再次進行比較判別。

if (str[k + 1] == str[q])//如果相同,k++

next[q] = k;//這個是把算的k的值(就是相同的最大字首和最大字尾長)賦給next[q]}}

這個和next很像,具體就看**,其實上面已經大概說完了整個匹配過程。

int kmp(char *str, int slen, char *ptr, int plen)

}return -1;

}

char *str = "bacbababadababacambabacaddababacasdsd";

char *ptr = "ababaca";

int a = kmp(str, 36, ptr, 7);

return

0;

注意如果str裡有多個匹配ptr的字串,要想求出所有的滿足要求的下標位置,在kmp演算法需要稍微修改一下。見上面注釋掉的**。

next函式計算複雜度是(m),開始以為是o(m^2),後來仔細想了想,cal__next裡的while迴圈,以及外層for迴圈,利用均攤思想,其實是o(m),這個以後想好了再寫上。

頂 8 踩

KMP演算法最淺顯理解 一看就明白

目錄 說明 kmp演算法求解什麼型別問題 演算法說明 解析 kmp測試 複雜度分析 進一步說明2018 3 14 kmp演算法看懂了覺得特別簡單,思路很簡單,看不懂之前,查各種資料,看的稀里糊塗,即使網上最簡單的解釋,依然看的稀里糊塗。我花了半天時間,爭取用最短的篇幅大致搞明白這玩意到底是啥。這裡不...

GIL對多執行緒的影響一看就明白

gil全稱global interpreter lock 全域性直譯器鎖 gil和python語言沒有任何關係,只是因為歷史原因導致在官方推薦的直譯器cpython中遺留的問題。多執行緒 每個執行緒在執行的過程中都需要先獲取gil,保證同一時刻只有乙個執行緒可以執行 但是當遇到io阻塞會自動的釋放g...

並查集 你一看就明白就會用

本文分成兩個部分,第一部分是基礎知識,這一塊這篇文章就講得非常好了,生動有趣又簡單易懂,是我見過的最好的演算法解說博文。既然它已經做到最好,我就沒必要做重複的事情了,就在這裡給大家點乙個方向。我要做的是第二部分,就是給出題型模板與刷題。我們不能光會理論,不知道怎麼應用。針對於並查集,我選的是力扣54...