问题概述:输入两个数n和m,再依次输入n个数作为串a,再输入m个数作为串b,请判断b串是否为a的子串,若是则输出b串在a串的起始点
输入样例: 对应输出:
2 6
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
KMP算法(专用于求解字符串匹配问题)步骤:
①定义一个数组next[m]用于对应子串(b[m]),next[i]=j表示b[1~j]和b[i-j+1, i]完全相等且b[i]!=b[j]
②初始化i=j=1(串中第一个)
③i++, j++,如果a[i]==b[i]执行步骤5,否则执行步骤4
④b串向后挪,由b[j]对应a[i]变为b[next[j]]对应a[i](j=next[j]),如果next[j]==-1则表示a[i]完全不能对应字串b中的任何一个元素,i++, j=0
⑤判定是否已经匹配完毕,如果没有继续执行步骤3
(在最后3个步骤中,如果i超过a的范围,表示匹配失败,结束)
原理:http://www.matrix67.com/blog/archives/115
复杂度:O(n+m)
#include<stdio.h>
#include<string.h>
int n, m;
int a[1000005], b[10005], next[10005];
void Getnext();
int KMP();
int main(void)
{
int T, i;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
for(i=1;i<=n;i++)
scanf("%d", &a[i]);
for(i=1;i<=m;i++)
scanf("%d", &b[i]);
if(n<m)
{
printf("-1\n");
continue;
}
Getnext();
printf("%d\n", KMP());
}
return 0;
}
void Getnext()
{
int i, j;
i = 1, j = 0;
next[1] = 0;
while(i<=m)
{
if(j==0 || b[i]==b[j])
{
i++, j++;
if(b[i]==b[j]) /*虽然到这里可以满足b[1~j]和b[i-j+1,i]完全相等,但是因为b[i]=b[j],如果b[i]无法匹配,那么b[j]一定无法匹配*/
next[i] = next[j];
else
next[i] = j;
}
else /*如果b[i]和b[j]不相等,则说明后面不可能存在在i-j=k(k为定值)的情况下b[1~j]和b[i-j+1,i]完全相等,拉开i与j的距离*/
j = next[j];
}
}
int KMP()
{
int i, j;
i = j = 1;
while(i<=n)
{
/* 统计数量
if(a[i]==b[j])
{
if(j==m)
{
ans++;
j = net[j+1];
i++;
}
else
i++, j++;
}
*/
if(a[i]==b[j]) /*匹配成功,i++,j++,继续匹配*/
{
if(j==m)
return i-j+1;
i++, j++;
}
else
{
j = next[j]; /*匹配不成功,b串向后挪,由b[j]对应a[i]变为b[next[j]]对应a[i],即j=next[j]*/
if(j==0) /*如果next[j]==-1表示a[i]完全不能对应字串b中的任何一个元素,i++,j=0*/
i++, j = 1;
}
}
return -1;
}