一道锻炼对于
k
m
p
kmp
kmp算法中的
p
m
t
pmt
pmt数组理解的题
题目链接
题目大意
给定字符串 s s s,需要找到字符串 t t t,使得 t t t满足以下条件: t t t既是 s s s的前缀也是后缀,同时在 s s s内部出现
思路
我们发现
t
t
t既是后缀又是前缀,这不就是
k
m
p
kmp
kmp中
p
m
t
pmt
pmt数组的定义嘛(大佬的博客也叫失配数组或next数组),所以我们可以先求出一个
p
m
t
pmt
pmt数组,然后到
s
s
s中找目标字串。
因为中间字串
t
t
t只能结束于
s
[
2
]
s[2]
s[2] ~
s
[
n
−
1
]
s[n-1]
s[n−1]之间,所以
t
t
t的长度也在
p
m
t
[
2
]
pmt[2]
pmt[2]~
p
m
t
[
n
−
1
]
pmt[n-1]
pmt[n−1]之间,所以我们求
p
m
t
pmt
pmt的时候顺便求一个长度最大值
m
a
ma
ma。
剩下的就是遍历小于等于
m
a
ma
ma的输出就行了,可以是复杂度
n
n
n的遍历,也可以是我下面写的方法
ACcode
#include<bits/stdc++.h>
using namespace std;
const int M = 1e6 + 9;
int pmt[M];
void get_pmt(const string& p) {
for (int i = 1, j = 0;i < p.size();i++) {
while (j && p[i] != p[j])j = pmt[j - 1];
if (p[i] == p[j])j++;
pmt[i] = j;
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
string str;cin >> str;
get_pmt(str);
int ma = 0;
for (int i = 1;i < str.size() - 1;i++)ma = max(ma, pmt[i]);
int k = pmt[str.size() - 1];//长度
while (k > ma)k = pmt[k - 1];
//为什么k=pmt[k-1]?
//因为现在的k是大于ma的,而我们要找的是小于ma的,所以直接跳到字符串长度为k的地方,因为我这个是string直接读取的字符串,所以下标就是k-1
if (k) {
for (int i = 0;i < k;i++)cout << str[i];
}
else {
cout << "Just a legend";
}
return 0;
}