學習筆記 KMP

2021-10-01 19:50:28 字數 2785 閱讀 1121

kmp用於在乙個字串中尋找乙個模式串。

kmp詳細講解

一:演算法思想(下標從0開始)

當我們需要在乙個字串中s找乙個模式串p是否出現的時候,最容易想到的就是暴力:列舉左端點,然後從這個點開始匹配,失敗則換下乙個左端點;如圖所示:我們先匹配了a b c並且都成功了。

但下一位d != a,所以我們需要重新在s中找下乙個起始點,再從p串第一位重新開始匹配:

直到匹配成功

但是這樣複雜度就會達到o(n^2),效率較低。實際上這種暴力是可以優化的,當我們第一次匹配失敗後,我們如果可以o(1)地知道下一次該匹配哪個字元那麼複雜度就會降低很多,和cf這道題的思想有點像於是就有了乙個針對於模式串p的next陣列,以便於我們在匹配失敗的時候可以o(1)地知道在保證答案正確的條件下,模式串p究竟該從**開始匹配;

事實上,我們根本沒有必要去匹配p[0]和s[1];因為從第一次匹配中我們可以得到乙個資訊:s[1]和p[1]匹配;而p這個串有乙個本身的固定屬性:p[1] != p[0];所以經過第一次匹配後我們就知道s[1]和p[0]必然失配,但前提是我們能夠p的這種屬性給處理出來,這也就是我們的next陣列;

二:next陣列

1.含義:next[i] 表示的是p[i]之前的最大相同字首字尾的長度。第乙個初始化為-1;例如:(2是整個字串的最大相同字首字尾的長度)。

有了next陣列,我們也就有了新的匹配規則:在s的位置i,p的位置j失配的時候,我們直接拿next[j]和i匹配,此時i位置之前的也一定匹配:

因為:next[j]表示的是p[j]之前字元最大相同字首字尾的長度,設其為k,可以推出:

p[0] p[1]…p[k-1] = p[j-k],p[j-k+1]…p[j-1].

又因為:p[0] p[1]…p[j-1] = s[i-j] s[i-j+1]…s[i-1];

所以從s的某個位置pos開始就有:

p[0] p[1] …p[k-1] = s[pos] s[pos+1] … s[i -1];

也就是說當p[j]和s[i]失配時,可以直接拿next[j],也就是p[k]和s[i]匹配,並且之前的字元也全部都是匹配的。這樣我們就可以快速找到下乙個匹配的位置,從而提高效率;

//匹配部分的**:在a中看b是否出現

bool

kmp(

)return

false

;}

2.求解:對於字串p,假設我們已經知道了next[i] =j,現在要求next[i + 1];

(1).p[i] == p[j] :則next[i + 1] = next[i] + 1 = j + 1; 如圖:紅色和藍色部分分別是i之前和j之前的相同字首字尾

(2).p[i] != p[j] :此時我們就需要去找更短一點的串,而這個串應該從p[0]~p[j]這一段來找,如圖(黃色部分相等,藍色部分相等,長度為j部分是p[i]之前的最長相等字首和字尾),此時p[j] != p[i],但是p[next[j]] = p[i],所以我們的next[i+1] = next[next[i]] + 1,不斷進行這種遞迴的方式,令j=next[j],直到j = -1或者p[i] = p[j]結束

//求解b的next陣列

void

kmp_pre()

}

但是這樣還可以優化:s[i]與p[j]失配的時候,令j=next[j] = k,即p[k]和s[i]匹配,萬一我們的p[k] = p[j] 那麼豈不是又是無用功,因此為了避免這種情況,我們還要檢測一下這兩貨是不是相等。相等的話next[i] = next[k];

void

kmp_pre()

}

next陣列還有一些用法值得注意。

利用next陣列求解迴圈節:假定乙個字串長度為len且len%(len-next[len])=0,那麼其最小迴圈節的長度為len-next[len],而且這個字串由該迴圈子串重複len/(len-next[len])構成;

如果len%(len-next[len])!=0,說明還要加一些才能成為迴圈字串,個數為l-len%l,l=len-next[len];

此外,因為l=len-next[len]可以由next[len]=len-l推出;就是說我們先假設乙個字串由乙個長度為l的串重複k次組成了長度為len的串,那麼len=k*l;next[len]表示這個串的最大相同字首和字尾的長度,不應該是整個字串的長度,所以無論k為奇還是偶都應該減去乙個迴圈節的長度l,所以next[len]=len-l;

KMP學習筆記

最近在搞這個東西,不知道為啥,看一遍sb一遍。終於在今天下午從宿舍裡猛的一起,狂奔到機房中,還在懵逼狀態下的我終於搞懂了這個演算法。縱觀全網,kmp雖然是個很老很經典的演算法,部落格關於它的講解也不少,我就把我的理解寫一遍,希望對大家有所幫助。首先kmp這個東西是幹啥使的呢?比如你在打亡者農藥,你方...

KMP 學習筆記

我們將待匹配的字串稱為主串,用來匹配的字串稱為模式串 模式串長度小於等於主串長度 設模式串p為 orzzorzo 主串s為 orzzorqworzzorzo 使用樸素演算法進行匹配時 表示匹配成功,表示在此字元失配 orzzorqworzzorzo orzzorzo首先,將兩串對齊,從左到右匹配p與...

學習筆記 KMP演算法

kmp演算法是一種可以在 o n m 的時間複雜度內實現兩個字串匹配的演算法。acwing 831.kmp字串 給定乙個模式串s,以及乙個模板串p,所有字串中只包含大小寫英文本母以及阿拉伯數字。模板串p在模式串s中多次作為子串出現。求出模板串p在模式串s中所有出現的位置的起始下標。輸入格式 第一行輸...