#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int maxn = 10005;
int f[maxn];
void getf1(string p)//可判断周期及循环数
{
memset(f, -1, sizeof(f));
f[0] = f[1] = 0;
for (int i = 1; i < p.size(); i ++) {
int j = f[i];
while (j && p[i] != p[j]) {
j = f[j];
}
f[i + 1] = p[i] == p[j] ? j + 1 : 0;
}
for (int i = 1; i <= p.size(); i ++) {
// cout << f[i] << " " ;
if (i % (i - f[i]) == 0 && f[i] > 0) {
cout << i - f[i] << " " << i / (i - f[i]) << endl;//周期长度 周期数
}
}
cout << endl;
}//getf1()
void match1(string t,string p)
{
getf1(p);
int j = 0;
for (int i = 0; i < t.size(); i ++) {
while (j && t[i] != p[j]) {
j = f[j];
}
if (t[i] == p[j]) {
j ++;
}
if (j == p.size()) {
cout << i - j + 1 << endl;
}
}
}//match1()
void getf3(string p)//据说省时
{
memset(f, -1, sizeof(f));
f[0] = f[1] = 0;
int i = 1,j = 0;
while(i < p.size()){
if (j == 0 || p[i] == p[j]) {
i ++;j ++;
if (p[i] == p[j]) {
f[i] = f[j];
}
else f[i] = j;
}
else j = f[j];
}
}//getf3()
void match3(string t,string p)
{
getf3(p);
int i = 0,j = 1;
while(i <= t.size() && j <= p.size()) {
if (j == 0 || t[i] == p[j]) {
i ++;j ++;
}
else j = f[j];
if (j == p.size()) {
cout << i - j << endl;
}
}
}//match23()
int main()
{
string s,t;
cin >> s >> t;
getf1(s);
match1(t, s);
getf3(s);
match3(t, s);
return 0;
}
KMP就像dfs,只是方法,题意变化,需要技巧转化。
poj1961
求给定字符串s,前i个字符,是否存在是字符串t的循环,循环次数k>1。求每种t的长度和k。
先求失配数组f[]。若i失配,则回到f[i],则s[f[i]..i]是s[1..i]的某个前缀,s[1..i]可能存在长度为(i - f[i])的字符串循环。
(i - f[i]) * k = i得到i % (i - f[i]) = 0。
且k > 1,即f[i] > 0。
poj2752
给定字符串s,求所有字符串a,为s的前缀后缀。即求所有k,使s[1..k] = s[sz - k + 1..sz]
失配数组f[].
q1 = f[sz],即s[1..q1] 与s[1..sz]最后q1个字符相同
q2 = f[q1],即s[1..q2] 与s[1..q1]最后q2个字符相同,即s[1..q2]与s[1..sz]最后q2个字符相同,即s[1..q2]同时为s的前缀后缀。
以此类推,至q = f[qx] = 0,没有一个字符相同,退出。