先记录一个小坑。
int KMP()
{getNext();int i = 0, j = 0;//写成下面这样,结果不对。原因是,当j=-1时,循环条件-1 < strlen(P)被认为是false,会跳出循环while (i < strlen(T) && j < strlen(P)) {if (j == -1 || T[i] == P[j]) { ++i, ++j; }else j = nxt[j];}return i - j;
}
改对的写法
int KMP()
{getNext();int n = strlen(T);int m = strlen(P);int i = 0, j = 0;while (i < n && j < m){if (j == -1 || T[i] == P[j]) { ++i, ++j; }else j = nxt[j];}return i - j;
}
KMP 串的模式匹配
给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出。如果找不到,则输出“Not Found”。
本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据0:小规模字符串,测试基本正确性;
- 数据1:随机数据,String 长度为 105,Pattern 长度为 10;
- 数据2:随机数据,String 长度为 105,Pattern 长度为 102;
- 数据3:随机数据,String 长度为 105,Pattern 长度为 103;
- 数据4:随机数据,String 长度为 105,Pattern 长度为 104;
- 数据5:String 长度为 106,Pattern 长度为 105;测试尾字符不匹配的情形;
- 数据6:String 长度为 106,Pattern 长度为 105;测试首字符不匹配的情形。
输入格式:
输入第一行给出 String,为由英文字母组成的、长度不超过 106 的字符串。第二行给出一个正整数 N(≤10),为待匹配的模式串的个数。随后 N 行,每行给出一个 Pattern,为由英文字母组成的、长度不超过 105 的字符串。每个字符串都非空,以回车结束。
输出格式:
对每个 Pattern,按照题面要求输出匹配结果。
输入样例:
abcabcabcabcacabxy
3
abcabcacab
cabcabcd
abcabcabcabcacabxyz
输出样例:
abcabcacabxy
Not Found
Not Found
code
# include <iostream>
# include <cstdio>
# include <cstring>char T[1000010]; //文本串
char P[100010]; //目标串
int nxt[100010]; //next数组void getNext()
{nxt[0] = -1; //哨兵:如果与P[0]都失配,那么文本串和模式串就要携手共进一位了for (int i = 0; i < strlen(P) - 1; ++i) //假设[0,i]已填好,现计算nxt[i+1]{int j = i;while (nxt[j] != -1 && P[i] != P[nxt[j]])j = nxt[j];nxt[i + 1] = nxt[j] + 1;}
}int KMP()
{getNext();int n = strlen(T);int m = strlen(P);int i = 0, j = 0;while (i < n && j < m){if (j == -1 || T[i] == P[j]) { ++i, ++j; }else j = nxt[j];}return i - j;
}int main(void)
{scanf("%s", T);int k;scanf("%d", &k);while (k--){scanf("%s", P);int pos = KMP();if (strlen(T) < strlen(P) || pos > strlen(T) - strlen(P)) printf("Not Found\n");else{for (int i = KMP(); T[i] != '\0'; ++i){printf("%c", T[i]);}printf("\n");}}return 0;
}