集训总结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不再给了,上面的链接点开会有很多很优秀的正解~~

 

posted @ 2018-05-30 20:55  ve-2021  阅读(112)  评论(0编辑  收藏  举报