集训总结DAY.1(18.5.22)——KMP
DAY 1——5.22
in the morning 依稀记得我们有一场contest。
at night
chf大佬讲KMP,先膜一波~
luoguP3375KMP模板题
KMP算法,又称模式匹配算法,能在线性时间内判定字符串S1[1~N]是否为字符串S2[1~M]的子串。
一、朴素的做法 O(M*N)
尝试枚举字符串S2中的每个位置i,把字符串S1与字符串S2的后缀S2[i~M]对齐,向后扫描逐一比较S1[1]与S2[i],S1[2]与S2[i+1]......是否相等。
string s1,s2;
//s1(n)>=s2(m)
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
//字符串下标从0开始
if(s1[i]==s2[j]) ...
}
}
二、Hash!
在O(N)的时间内预处理一个字符串的所有前缀Hash值,并在O(1)的时间内查询该字符串任意子串的Hash值。枚举S1中的每个位置i(M<=i<=N),检查字符串S2中的Hash值与字符串A中的子串S1[i-M+1~i]的Hash值是否相同。
那么,什么是KMP?
1.对字符串S1进行自我匹配,求出一个数组next,其中next[i]表示“S1中以S1结尾的非前缀子串(有i-1个)”与“S1的前缀”能够匹配的最长长度。
如S1[2~i]与S1[1~i-1],S1[3~i]与S2[1~i-2]......
由此依次匹配对比,若得出的最大匹配值为k(即为参与比较的字串长度,若匹配,则其长度为匹配值),next[i]=k;
next[i]=max{j},其中j<i并且S1[i-j+1~i]=S1[1~j]
求next数组
(1)初始化next[1]=j=0,假使next[1~i-1]已求出,求解next[i]。
(2)不断尝试扩展匹配长度j,如果扩展失败(下一个字符不相等),令j变为next[j],直至j变为0(应该重新从头开始匹配)。
(3)如果能匹配成功,匹配长度j就增加1.next[i]的值就是j。
对于next数组,老师在讲课时又提出了几个问题,能加深理解:
想清楚再看答案哦
question:next[i]是否能大于next[i-1]+1? why?
answer: of course not.因为i表示从1~i的前缀能匹配的最长字符个数。
next[1]=0;
for(int i=2,j=0;i<=n;i++)
{
while(j>0&&a[i]!=a[j+1]) j=next[j];
if(a[i]==a[j+1]) j++;
next[i]=j;
}
2.对字符串S1与S2进行匹配,求出一个数组f,其中f[i]表示“S2中以i结尾的子串”与“S1的前缀”能够匹配的最长长度。
f[i]=max{j},其中j<=i并且S2[i-j+1~i]=S1[1~j]
(其实求解f和next是很像的,自己写看看)
完整code不再给了,上面的链接点开会有很多很优秀的正解~~