参考:https://www.zhihu.com/question/21923021/answer/281346746
KMPアルゴリズムのフロント:なし
KMPアルゴリズムは、所与の長さのパターン列P S nのメイン文字列の長さmを見つけるため、時間複雑度は、O(N×m個)から最適化することができ、アルゴリズムに一致する効率的な文字列であり、Oであります(N + M)。
コアKMPアルゴリズムは、アレイ(以下、PMTと略記する)部分一致テーブル(部分マッチテーブル)と呼ばれます。そのPMT以下図値、要素の最も長い一連の交差点を設定する接頭辞と接尾辞の文字列の長さのPMT値に示すように、文字列「abababca」のため。
で、文字列P = "abababca" ホスト文字列S = "ababababca" をマッチングして下さい。もしそうでない文字jにおいて、メインストリングのポインタの前にPMTと一致する上記文字列、PMTの性質iが[J-1]ビットは、[特定の一致する文字列のPMTに0ビットでありますJ-1]は同じ位置です。
図の例では、ミスマッチIにおいて、同一のメイン文字列と一致する文字列の最初の6桁は、そのように。そして、文字列が最初の6ビットと一致するため、接頭辞と接尾4後の最初の4ビットが同じであるので、私4と弦4の開始が同じである前に、我々は、メインの文字列を推測します。グレイは図の一部であり、この部分は比較にならないだろうと。
以前のアイデアを、我々は検索PMTは、文字列を加速することができます。便宜のために、我々は直接PMTアレイを使用していないが、PMTアレイを後退するようjビットの不一致ならば、衝撃Jポインターバック位置は、実際には第J-1 PMTビット値です。私たちは、この新しい配列は次の配列と呼ばれ得ます。
上記の例では、次の配列は、図2に示すように。我々はPMTで後方にシフトして、ビット0の値が-1に設定されている場合、我々はプログラミングを容易にすることを目指しています。
其实,求next数组的过程完全可以看成字符串匹配的过程,即以匹配字符串为主字符串,以匹配字符串的前缀为目标字符串,一旦字符串匹配成功,那么当前的next值就是匹配成功的字符串的长度。具体来说,就是从匹配字符串的第1位(注意,不包括第0位)开始对自身进行匹配运算。在任一位置,能匹配的最长长度就是当前位置的next值,如下图所示。
例题:
HDU1711 Number Sequence
Problem Description
Given two sequences of numbers: a[1], a[2], ...... , a[N], and b[1], b[2], ...... , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], ...... , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one.
Input
The first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], ...... , a[N]. The third line contains M integers which indicate b[1], b[2], ...... , b[M]. All integers are in the range of [-1000000, 1000000].
Output
For each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead.
Sample Input
2
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 2 1
Sample Output
6
-1
参考代码:
#include <stdio.h>
#include <string.h>
int n, m;
int a[1000005], b[10005], next[10005];
void buildnext()
{
next[0] = -1;
int i = 0, j = -1;
while (i < m)
{
if (j == -1 || b[i] == b[j])
next[++i] = ++j;
else
j = next[j];
}
}
int kmp()
{
buildnext();
int i = 0, j = 0;
while (i < n && j < m)
{
if (j == -1 || a[i] == b[j])
{
++i;
++j;
}
else
j = next[j];
}
if (j == m)
return i - j;
else
return -1;
}
int main()
{
int t, i, ret;
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);
for (i = 0; i < n; ++i)
scanf("%d", &a[i]);
for (i = 0; i < m; ++i)
scanf("%d", &b[i]);
ret = kmp();
if (ret >= 0)
printf("%d\n", ret + 1);
else
printf("-1\n");
}
return 0;
}