上个星期刚复习完kmp,感觉一段时间不写就又生疏了
链接:
【模板】KMP - 洛谷
理解部分(无码)
最长相同(公共)子串//border
这个名词有点拗口,但是已经精准地道出了border的性质:
最长--目前最长的、相同--从左往右完全相同、子串--来自同一段字符串的子串
理解kmp的第一步就是理解这个最长公共子串是什么
值得注意的是,比较前后缀的时候,中间部分不必严格对称。
ABCABC//前后缀最长相同值为3
ABCBDEWAB//前后缀最长相同值为2(中间没影响最后的比较)
next数组(也叫border数组)
在不同风格的解法中,next数组是不同的。我们这里为避免混淆,只推荐最经典泛用的数组。
即:下标从0开始,且下标代表最长公共前后缀的长度。
next的构建,其实与两字符串的比较大同小异。说白了,题目要求的是两个字符串的比较,next的构建过程就是自己和自己比较。
不过对于新手来说,独立构建next数组难度略大,很多细节如条件判断的顺序,比较难安排
代码部分
next/border 创建:
string s2;//被比较的小子串
int size=s2.size();
int next[size]={0};
for(int i=1,j=0;i<size;++i)//i在右面,而且永远右移,而j经常回退
{
while(j&&s2[i]!=s2[j]){
j=next[j-1]; //这个回退新手能拿捏住吗?
}
if(s2[i]==s2[j])
++j;//匹配成功则j右移
next[i]=j;
}
比较s1,s2:
string s1;
int size=s1.size();
for(int i=0,j=0;i<Len1;++i){//这里就要从0开始了,因为每一位都要比较。
while(j&&s1[i]!=s2[j]){
j=border[j-1];
}
if(s1[i]==s2[j]){
++j;
}
if(j==size){
cout<<i+2-j<<endl;
}//大同小异
如果你已经比较深入了解这种算法,应该会了然两段代码其实有着相同的本质