题意:给两串序列,求出第二串序列在第一串序列中第一次出现的位置(序列头在第一串序列中的位置),不存在则输出-1
思路:KMP算法裸题。KMP算法维护一个fail数组,储存某点之前的最长公共前缀后缀的位置,若匹配到某点时失配,则不会从匹配序列头开始重新匹配下一个待配字符,而是从fail指针指向的节点开始匹配。AC自动机就是利用这个原理在Trie树上改进得到的。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
const int inf = 0x3f3f3f3f;
int n, m, fail[maxn], s[maxn], p[maxn], T;
void getFail()
{
fail[0] = -1;
int k = -1, j = 0;
while (j < m - 1) {
if (k == -1 || p[j] == p[k]) {
j++;
k++;
if (p[j] != p[k])
fail[j] = k;
else
fail[j] = fail[k];
}
else
k = fail[k];
}
}
int kmp()
{
int i = 0, j = 0;
while (i < n && j < m) {
if (j == -1 || s[i] == p[j]) {
i++;
j++;
}
else
j = fail[j];
}
if (j == m)
return i-j;
else
return -1;
}
int main()
{
scanf("%d", &T);
for (int t = 0; t < T; t++) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%d", &s[i]);
for (int i = 0; i < m; i++)
scanf("%d", &p[i]);
getFail();
int res = kmp();
res = res == -1 ? -1 : res+1;
printf("%d\n", res);
}
}