题目链接
题意
对于给定的两个字符串
T
与
法一:kmp
思路
对
P
求
注意在中间就匹配成功时处理一下。
Code
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
typedef long long LL;
char T[maxn], P[maxn], ans[maxn];
int f[maxn], n, m;
void getfail() {
f[0] = f[1] = 0;
for (int i = 1; i < m; ++i) {
int j = f[i];
while (j && P[i] != P[j]) j = f[j];
f[i+1] = P[i] == P[j] ? j+1 : 0;
}
}
int kmp() {
int j = 0;
for (int i = 0; i < n; ++i) {
while (j && T[i] != P[j]) j = f[j];
if (T[i] == P[j]) ++j;
if (j == m && i != n-1) j = f[j];
}
return j;
}
void work() {
memset(ans, 0, sizeof ans);
n = strlen(T), m = strlen(P);
getfail();
int len = kmp();
if (len == 0) printf("0\n");
else {
memcpy(ans, P, len*sizeof(char));
printf("%s %d\n", ans, len);
}
}
int main() {
while (scanf("%s%s", P, T) != EOF) work();
return 0;
}
法二:fail 数组妙用
参考
hdu KMP中级题目总汇 ——Because Of You
思路
将两个字符串拼接起来,即变成了求一个字符串的后缀与前缀的最大匹配长度,即为 fail 数组的含义。
注意这个长度必然不大于两个字符串长度的最小值,所以要处理一下。(也可以在中间插入特殊字符)
Code
#include <bits/stdc++.h>
#define maxn 200010
char T[maxn], P[maxn], ans[maxn];
int f[maxn], n, m;
using namespace std;
typedef long long LL;
void getfail() {
f[0] = f[1] = 0;
for (int i = 1; i < m; ++i) {
int j = f[i];
while (j && P[j] != P[i]) j = f[j];
f[i+1] = P[j] == P[i] ? j+1 : 0;
}
}
void work() {
n = strlen(T), m = strlen(P);
int mn = min(n, m);
strcat(P, T);
m += n; getfail();
while (f[m] > mn) m = f[m];
if (f[m] == 0) printf("0\n");
else {
memset(ans, 0, sizeof ans);
memcpy(ans, P, f[m]);
printf("%s %d\n", ans, f[m]);
}
}
int main() {
while (scanf("%s%s", P, T) != EOF) work();
return 0;
}
感慨
fail 数组好物也!
尤其要注意 fail 数组本身的含义,在涉及到 前缀 与 循环节 的题目中要联想到。