const int N = 100000;
/*
KMP 算法模板
时间复杂度 : O(n+m) [其中 n,m 是两字符串的长度]
说明:
1. a是长串 s是短串 即 a.length >= s.length
2.实现了“查找第一次匹配的位置” “匹配的次数” “记录所有匹配区间”三个功能
3.三个功能的实现代码非常相似,第3个功能可以同时实现前2个的功能
*/
struct KMP
{
int f[N + 7];
void getfill (string s) //预处理
{
memset (f, 0, sizeof (f) ); //根据其前一个字母得到
for (int i = 1; i < s.length(); i++)
{
int j = f[i];
while (j && s[i] != s[j])
j = f[j];
f[i + 1] = (s[i] == s[j]) ? j + 1 : 0;
}
}
int finds (string a, string s) //找到第一次匹配的位置 a.length >= s.length
{
getfill (s);
int j = 0;
for (int i = 0; i < a.length(); i++)
{
while (j && a[i] != s[j]) j = f[j];
if (a[i] == s[j]) j++;
if (j == s.length() )
{
return i - s.length() + 1; //返回小串在大串中第一次出现的位置
}
}
return -1;//不匹配返回-1
}
int findtimes(string a,string s)//返回匹配次数
{
getfill(s);
int j = 0;int times = 0;
for (int i = 0;i < a.length();++i)
{
while (j&&a[i] != s[j]) j = f[j];
if (a[i] ==s[j]) j++;
if (j == s.length())
{
times++;
}
}
return times;//不匹配的times将是0
}
struct Interval
{
int l,r;
}q[N];//记录所有匹配区间 [指在长串中的下标,下标从0开始]
int t;//记录匹配次数
void findinterval(string a,string s)//找到并记录所有的匹配区间
{
getfill(s);
int j = 0;t = 0;
for (int i = 0;i < a.length();++i)
{
while (j&&a[i]!=s[j]) j = f[j];
if (a[i] == s[j]) j++;
if (j == s.length())
{
t++;
q[t].l = i - s.length() + 1;
q[t].r = i;
}
}
}
void Print()//第3种功能附带打印功能
{
cout<<"两串匹配了 "<< t <<"次,分别是 :"<<endl;
for (int i = 1;i <= t;++i)
{
cout<<"第"<<i<<"次 : ["<<q[i].l<<","<<q[i].r<<"]\n";
}
}
}kmp;