本专栏持续输出数据结构题目集,欢迎订阅。
题目
给定两个由英文字母组成的字符串 string 和 pattern,要求找到 pattern 在 string 中第一次出现的位置,并将此位置后的 string 的子串输出。如果找不到,则输出“Not Found”。
本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据0:小规模字符串,测试基本正确性;
- 数据1:随机数据,String 长度为 10
^
5,Pattern 长度为 10; - 数据2:随机数据,String 长度为 10
^
5,Pattern 长度为 10^2; - 数据3:随机数据,String 长度为 10
^
5,Pattern 长度为 10^3; - 数据4:随机数据,String 长度为 10
^
5,Pattern 长度为 10^4; - 数据5:String 长度为 10^6,Pattern 长度为 10
^
5;测试尾字符不匹配的情形; - 数据6:String 长度为 10^6 ,Pattern 长度为 10
^
5;测试首字符不匹配的情形。
输入格式:
输入第一行给出 string,为由英文字母组成的、长度不超过 10^
6 的字符串。第二行给出一个正整数 n(≤10),为待匹配的模式串的个数。随后 n 行,每行给出一个 pattern,为由英文字母组成的、长度不超过 10^5 的字符串。每个字符串都非空,以回车结束。
输出格式:
对每个 pattern,按照题面要求输出匹配结果。
输入样例:
abcabcabcabcacabxy
3
abcabcacab
cabcabcd
abcabcabcabcacabxyz
输出样例:
abcabcacabxy
Not Found
Not Found
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int la, lb; // 主串和模式串的长度
int next[1000001]; // KMP算法的next数组
char a[1000001], b[1000001]; // 主串和模式串(下标从1开始)
// 计算模式串的next数组(部分匹配表)
void Next() {
int i, j = 0;
for (i = 2; i <= lb; i++) {
// 不匹配时回溯到上一个可能位置
while (j > 0 && b[i] != b[j + 1]) {
j = next[j];
}
if (b[i] == b[j + 1])
j++;
next[i] = j;
}
}
// KMP算法实现:在主串a中查找模式串b的首次出现
int KMP(char a[], char b[]) {
int j = 0, t = 0, l = -1; // l=-1表示未找到匹配
for (int i = 1; i <= la; i++) {
// 不匹配时回溯到next数组指示的位置
while (j > 0 && b[j + 1] != a[i]) {
j = next[j];
}
if (b[j + 1] == a[i])
j++;
// 找到完整匹配
if (j == lb) {
t = i - lb + 1; // 记录匹配起始位置
l = 0; // 标记已找到
break;
}
}
// 输出匹配位置后的子串
if (l == 0) {
for (; t <= la; t++) {
printf("%c", a[t]);
}
}
return l; // 返回是否找到的标志
}
int main() {
scanf("%s", a + 1); // 主串从下标1开始存储
la = strlen(a + 1); // 计算主串长度
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%s", b + 1); // 模式串从下标1开始存储
lb = strlen(b + 1); // 计算模式串长度
Next(); // 预处理next数组
int m = KMP(a, b); // 执行KMP匹配
if (m == -1)
printf("Not Found");
if (i != n - 1) // 最后一个结果后不输出额外换行
printf("\n");
}
}