kmp即字符串匹配,时间复杂度O(M+N)。
核心为求匹配的字符串的next[]数组(以当前位置结束的最长前缀的位置),代码如下:
void getnext()
{
int i=0,j=-1,len=strlen(str2);
a[0]=-1;
while(i<len)
{
if(j==-1||str2[i]==str2[j])
a[++i]=++j;
else
j=a[j];
}
}
裸题:hdu1686
查一串字符串中某个单词的出现次数。
输入
第一行输入一个 T ,代表数据数目。
每组数据第一行输入需要查找的单词。
第二行输入这个较长的字符串(长度小于1000010)。
输出
每组数据输出一个 n ,代表要这个单词出现的次数。
样例输入
3 ABCD ABCD AZA AZAZAZA HIDSJ FJOSJWHABNMDS
样例输出
1 3 0
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
char str1[maxn],str2[maxn];
int a[maxn];
void getnext()
{
int i=0,j=-1,len=strlen(str2);
a[0]=-1;
while(i<len)
{
if(j==-1||str2[i]==str2[j])
a[++i]=++j;
else
j=a[j];
}
}
int kmp()
{
int ans=0,i=0,j=0,l1=strlen(str1),l2=strlen(str2);
while(i<l1)
{
if(j==-1||str1[i]==str2[j])
i++,j++;
else
j=a[j];
if(j==l2)ans++;
}
return ans;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>str2>>str1;
getnext();
cout<<kmp()<<endl;
}
}
hdu2594
题意:
给两个字符串s1,s2,求最长的s1前缀匹配s2后缀的字符串,以及长度
输入
输入有多组数据。
每组数据有两行,分别为两个人的名字(名字全由英文组成,名字长度不超过50000)。
输出
求出前一个人的名字的前缀,与后一个人的名字的前缀,最大的相同数目。
若不为0,还需输出其相同的几位字母,并且字母在数字前面,中间由空格隔开。
样例输入
mike aniom kiava dvakia dasds fdsgh
样例输出
m 1 kia 3 0
思路:先把两串合并在一起,然后求next[]数组,然后判断next[]最后一位,如果长度>最短串的长度,就缩进到前面(即切断过长的部分)
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
string str1,str2,str3;
int a[maxn];
void getnext()
{
int i=0,j=-1,len=str3.size();
a[0]=-1;
while(i<len)
{
if(j==-1||str3[i]==str3[j])
a[++i]=++j;
else
j=a[j];
}
}
int main()
{
while(cin>>str1>>str2)
{
str3=str1+str2;
int lena=str1.size();
int lenb=str2.size();
int lenc=str3.size();
int ab=min(lena,lenb);
getnext();
while(a[lenc]>ab)
lenc=a[lenc];
if(a[lenc])
{
for(int i=0;i<a[lenc];i++)
cout<<str1[i];
cout<<" "<<a[lenc]<<endl;
}
else
{
cout<<a[lenc]<<endl;
}
str1.clear();
str2.clear();
str3.clear();
}
}
hdu4763
题意描述:给定一个字符串,找出长度最大的子串,使开始、中间、结尾至少都包含它?
思路:
从大到小枚举子串长度,先判断结尾和开始是否一样,如果一样,则使用kmp判断中间是否含有子串,如果有就是答案
代码:
#include<bits/stdc++.h>
using namespace std;
char s[1000005];
int nxt[1000005];
int len;
set<int> st;
void getnxt()
{
memset(nxt,-1,sizeof(nxt));
nxt[0] = -1; int j = -1;
for(int i = 0; i < len;){
if(j == -1||s[i] == s[j])nxt[++i] = ++j;
else j = nxt[j];
}
}
void getback()
{
int p = nxt[len-1];
while(p>=0){
if(s[len-1] == s[p]){
st.insert(p+1);
}
p = nxt[p];
}
}
void solve()
{
int ans = 0;
for(int i = len-2;i>=0;--i){
int p = nxt[i];
while(p>=0){
if(s[i] == s[p] && st.find(p+1)!=st.end()){
if(len - 1 -p > i && p < i-p){
ans = max(ans,p+1);
}
}
p = nxt[p];
}
}
printf("%d\n",ans);
}
int main()
{
int T;
cin>>T;
while(T--){
cin>>s;
st.clear();
len = strlen(s);
getnxt();
getback();
solve();
}
return 0;
}
以上为kmp总结例题。