本题求s2在s1中出现的所有位置,即匹配成功后仍需要进行比对,直到扫描完主串。
next数组,ne[i]=j是模式串以i为结尾的所有后缀中与所有前缀匹配的最长序列长度为j,如:abcdabc 以最后一个字符为后缀的所有后缀和该串的前缀匹配的序列有:abc、bc、c,显然abc为长度最长。
next数组应用:当模式串第i位失配时,移动模式串到j位再进行比对。在上例中就是最后一个字符失配后,模式串指针移动到模式串最长前缀abc的c位置
作用:避免蛮力算法的局部匹配信息的浪费和必然不匹配的比对
next数组的构造要对模式串进行。
const int N=1e6+10,M=1e6+10;
int ne[N];char s[N],t[N];//s为主串,t为模式串
for(int i=2,j=0;t[i];i++){//由于ne[1]=0,即模式串第一个字符不匹配,则返回通配符,故ne从2开始求
while(j&&t[i]!=t[j+1])j=ne[j];
if(t[i]==t[j+1])j++;
ne[i]=j;
}
而模式串和主串的比对过程和next数组的构造相似,完整代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=1e6+10;
int ne[N];char s[N],t[N];
int main(){
cin>>s+1;
cin>>t+1;
for(int i=2,j=0;t[i];i++){//由于ne[1]=0,即模式串第一个字符不匹配,则返回通配符,故ne从2开始求
while(j&&t[i]!=t[j+1])j=ne[j];
if(t[i]==t[j+1])j++;
ne[i]=j;
}
for(int i=1,j=0;s[i];i++){//如果遍历完主串,则搜索告终
while(j&&s[i]!=t[j+1])j=ne[j];
if(s[i]==t[j+1])j++;
if(!t[j+1]){//如果遍历完模式串,则得到一次匹配
cout<<i-j+1<<endl;
j=ne[j];//后移模式串,找下一次匹配
}
}
for(int i=1;t[i];i++)
cout<<ne[i]<<' ';
cout<<endl;
return 0;
}