把O(N*M)立减到O(N+M)的匹配算法,有没有好厉害的样子!结果next数组什么的,看的时候简直醉了。。
鉴于1711纯裸,那就借这个说说~也不知道自己到底有木有懂==
题意即给出两串数字,暂叫他a串和b串吧~要求输出b串与a串开始匹配的位置
比如那个样例
1 2 1 2 31 2 3 1 3 2 1 2
1 2 3 1 3
从第6位开始,所以输出6
当然很简单呀,两个循环一位一位比下去不就得了?
看这范围1 <= M <= 10000, 1 <= N <= 1000000,Time Limit: 10000/5000 MS (Java/Others),还敢暴力吗?
kmp基本思想就是把用不着重复比较的部分跳过去
bf的第二轮:
1 2 1 2 31 2 3 1 3 2 1 2
1 2 3 1 3
kmp的第二轮:
1 2 1 2 31 2 3 1 3 2 1 2
1 2 3 1 3
嗯,其实那个2完全可以直接跳过是把~
所以感觉kmp就是找出应该跳过哪一些,这就是通过next数组实现的~
void getnext(int *b,int *next)
{
next[0]=next[1]=0;
for(int i=1;i<M;i++)
{
int j=next[i];
while(j&&b[i]!=b[j])
j=next[j];
next[i+1]=(b[i]==b[j]?j+1:0);
}
}
这个next其实相当于在比较之前就已经初始化好了,计算嘛,是根据什么前缀后缀是否一样来的,详细解释篇幅会很多诶,反正网上资料很多哒~
嗯,next初始化好了,就要开始比较了,如何机智的避开不需要比较的那些元素呢?
int kmp(int *a,int *b,int *next)
{
getnext(b,next);
int j=0;
for(int i=0;i<N;i++)
{
while(j&&a[i]!=b[j])
j=next[j];
if(a[i]==b[j])
j++;
if(j==M)
{
return i+1-M+1;
}
}
return -1;
}
i,j还是俩指针,跳着指
嗯,就是这样,鉴于标题,再发个1711的主函数~
int main()
{
int T;
int po;
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(next,0,sizeof(next));
scanf("%d%d",&N,&M);
//if(N<M){printf("-1\n");continue;}
for(int i=0;i<N;i++)
scanf("%d",&a[i]);
for(int j=0;j<M;j++)
scanf("%d",&b[j]);
po=kmp(a,b,next);
printf("%d\n",po);
}
return 0;
}