kmp從入門到放棄

2021-07-15 17:23:20 字數 3981 閱讀 1251

標籤 : kmp、擴充套件kmp

給你兩個字串,你需要回答,b串是否是a串的子串(a串是否包含b串)。

a= 「aaaaaaaaaaaaaaaaaaaaaaaaaab」,b=」aaaaaaaab」 (最壞狀態)

o (mn): 一般做法

for (列舉b在a串中的起始位置)

for(向後比較ab是否相等)

……

o(n+m):傳說中的kmp演算法。

之所以叫做kmp,是因為這個演算法是由knuth、morris、pratt三個提出來的,取了這三個人的名字的頭乙個字母。

void getnext (int l,char *s)

}

ps.給大家補幾個圖,希望有助於大家理解。

(科赫曲線)

int kmp(int n, char *s, int

m, char *t)

}return cnt;

}

pku 3461 oulipo

題意:求乙個匹配串t在目標串s中的出現次數。

題解:求出t的next陣列,然後和s進行kmp匹配,匹配時當j=m的時候表示找到乙個可行解,計數器+1,然後將next[j]賦值給j,使得它的最長字首能夠繼續和目標串進行匹配。

海哥的題

(海哥2.0) hdu 2594 simpsons』 hidden talents

題意:給定兩個長度不大於50000的串,求兩個串的乙個最長公共子串滿足子串為第乙個串的字首,並且為第二個串的字尾。

題解:將s2連在s1的後面,再對字串求next陣列

#注意# s1和s2相連時可能連線的部分出現額外的匹配

如:(abd) (cab qqqq abdcab)

解決方法:

1、用乙個從未使用過的字元鏈結s1和s2 => abd cab*qqqqabdcab

2、在處理之後

u=next[len1+len2];

while(u>min(len1,len2))u=next[u];

pku 2406 power strings

題意:給定乙個長度不超過n(n <= 106)的字串,它一定是某個串重複k次得到,求這個k的最大值。

題解:假設子串t重複k次後得到串s,那麼t的長度一定為l = n/k(要整除),則t=s[1...l],將s拆分成k份,每份長度為l,則有

s[1...l] = s[l+1...2l] = s[2l+1...3l] = ... = s[(k-1)l+1...kl]

由於要保證k最大,勢必l要取最小,所以根據next函式的定義,有next[kl] = (k-1)l;即next[n] = n - l,所以l = n - next[n];

但是得出的長度l還要保證能被n整除,所以如果不能整除說明l = n,即k = 1;而如果能整除,那麼k = n / (n - next[n]);

hdu 3374 string problem

題意:給定乙個長度為n(n <= 106)的字串s,然後將它進行左移,總共產生n個迴圈字串,求其中字典序最小的串的編號以及這樣的串的個數,和字典序最大的串的編號以及這樣的串的個數。

題解:kmp+最大最小表示法

先求最小最大字典序

定義兩個指標i,j,i初始為0,j初始為1,再定義乙個長度變數k = 0:

1) 比較s[i+k] 和s[j+k]的大小關係:

a) 如果相等,k自增1;當k==n則跳出迴圈,否則繼續1)的比較;

b) 如果s[i+k] < s[j+k],j += k + 1, k = 0;

c) 如果s[i+k] > s[j+k], i += k + 1, k = 0;

2) 如果i 和j相等,j自增1;當j==n或i==n則跳出迴圈,否則繼續1)的比較;

這樣迴圈結束後如果,取i和j的小者就是答案。
(1)然後在利用求出來的下標,生成乙個新的字串作為匹配串和乙個原串的兩倍的串作為目標串進行kmp匹配,得到種數。

(2)直接用next陣列求出迴圈節,再計算出週期即可。

#include 

#include

#include

#include

#include

using

namespace

std;

int l,ne[2000007],pmax,pmin,ans;

char s[2000007];

int find_min_max(bool ifmin)

else

if (s[i+k]if (ifmin)

j+=k+1;

else i+=k+1;

k=0;

}else

if (i==j)

}return min (i,j);

}void getnext()

}void work ()

int main ()

return

0;}

6.pku 3690 constellations

題意:給定n*m(n<=1000, m <= 1000)的01矩陣s,再給定t(t <= 100)個p*q(p <= 50, q <= 50)的01矩陣,問p*q的矩陣中有多少個是s的子矩陣。

題解:由於p <= 50,所以我們可以把所有p*q的矩陣進行二進位制位壓縮,將p*q的矩陣的每一列壓縮成乙個64位整數,這樣p*q的矩陣就變成了乙個長度為q的整數序列t,用同樣的方式對n*m的矩陣進行壓縮,總共可以產生(n-p+1)個長度為m的整數序列,剩下的就是進行最多(n-p+1)次kmp匹配了。

擴充套件的kmp問題

給定母串s,和子串t。

容易發現,如果有某個位置i滿足extend[i]=m,那麼t就肯定在s中出現過,並且進一步知道出現首位置是i——而這正是經典的kmp問題。

因此可見「擴充套件的kmp問題」是對經典kmp問題的乙個擴充和加難。

aaaaabaa

aaaaaa

extend[1]=5 (6次運算)

aaaaabaa

aaaaaa

extend[2]=4 (?次運算)

next[2]=5

s[1..5]=t[1..5]

=>

t[2..6]=t[1..5]

t[2..5]=t[1..4]

s[2..5]=t[1..4]

t[2]開始的比較是完全可以避免前4次比較,我們直接從s[6]→t[5]開始比較。這時候一比較就發現失配,因此extend[2]=4

設extend[1..k]已經算好,並且在以前的匹配過程中到達的最遠位置是p。最遠位置嚴格的說就是i+extend[i]-1的最大值,其中i=1,2,3,…,k;不妨設這個取最大值的i是a。

設next[i]為滿足b[i..i+z-1]==b[0..z-1]的最大的z值(也就是b的自身匹配)。設目前next[0..lenb-1]與ex[0..i-1]均已求出,要用它們來求ex[i]的值。

設p為目前a串中匹配到的最遠位置,k為讓其匹配到最遠位置的值(或者說,k是在0<=i0

void getextand(const eletype str, int strlen, int extand, const eletype mode, int modelen, int

next)

else extand[i] = next[i - a];}}

小結:

1、kmp演算法充分利用已知資訊

2、「字串」

beego 從入門到放棄

beego 的專案基本都是通過 bee命令來建立的,所以在建立專案之前確保你已經安裝了 bee 工具和 beego。如果你還沒有安裝,那麼請查閱 beego 的安裝 和 bee 工具的安裝 現在一切就緒我們就可以開始建立專案了,開啟終端,進入 gopath src 所在的目錄 建立乙個專案名為201...

Flutter從入門到放棄

本篇主要記錄下flutter的學習路線。一 認識flutter 可以檢視這些文章 二 dart語言 1 認識dart語言 2 學習 從2018.02開始出現dart2,屬於強型別語言。介紹位址參考 三 開始flutter 網上也有很多部落格介紹了flutter怎麼安裝,但大多介紹不全,第一次安裝難免...

python 從入門到放棄

本人所有關於python的內容均為學習期間的整理的筆記,希望可以給學習者帶來些許幫助!不過一入it深似海!準備入行者請做好充分的心理準備!計算機的知識跟新迭代速度很快,不學習就會被淘汰!如果你打算入行然後找乙份安穩的工作安度餘生,那麼我還是建議去考公務員吧!這個行業可能並不適合你!有不少的人可能都覺...