字符串匹配
主要参考:
http://www.ruanyifeng.com/blog/2013/05/Knuth–Morris–Pratt_algorithm.html
理解KMP 的9张PPT:http://weibo.com/1580904460/BeCCYrKz3#_rnd1405957424876
https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html
假设模式串为P,原串为S
1 朴素方法
最坏时间复杂度:O(P.length*S.length)
2 KMP
时间复杂度:O(P.length+S.length)
KMP算法步骤:
1.构造next数组
2.将模式串和原串进行匹配
3 KMP相关练习
3道都是模板题,大差不差,主要在于巩固,加深记忆。
算法练习1 #1015 : KMP算法
http://hihocoder.com/problemset/problem/1015
#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 10005
int next1[MAXN];
//得到next1数组 next1[j]表示字符子串(0~j)中前缀后缀相等的最长字符个数(-1表示0个字符相等,0表示有1个字符相等,以此类推)
void getNext(string s1)
{
next1[0] = -1;
int t;
int len1 = s1.size();
for(int j = 1; j < len1; j++)
{
t = next1[j-1];
while(t >= 0 && s1[j] != s1[t + 1])
{
t = next1[t];
}
if(s1[j] == s1[t + 1])
{
next1[j] = t + 1;
}
else
{
next1[j] = -1;
}
}
/*
cout<<"---"<<endl;
for(int i = 0;i<len1;i++)
{
cout<<next1[i]<<endl;
}
cout<<"---"<<endl;
*/
}
//s1表示模式串 s2表示原串
int kmp(string s1, string s2)
{
int cnt = 0;
int i = 0, j = 0;
int len1,len2;
len1 = s1.size();
len2 = s2.size();
while(i < len2)
{
if(s1[j]==s2[i])
{
j++;i++;
if(j == len1)
{
cnt++;
j = next1[j-1] + 1;
}
}
else
{
if(j == 0)
i++;
else
j = next1[j-1] + 1;
}
}
return cnt;
}
int main() {
int T;
cin>>T;
string s1, s2;
while(T--)
{
cin>>s1>>s2;
getNext(s1);
int cnt = kmp(s1,s2);
cout<<cnt<<endl;
}
return 0;
}
算法练习2 P3375 【模板】KMP字符串匹配
https://www.luogu.org/problemnew/show/P3375
#include <iostream>
using namespace std;
#define MAXN 1000005
int next1[MAXN];
int main() {
// your code goes here
//s1表示原串 s2表示模式串
string s1,s2;
cin>>s1>>s2;
int len1 = s1.size();
int len2 = s2.size();
int t;
next1[0] = -1;
for(int j = 1; j < len2; j++)
{
t = next1[j - 1];
while(t >= 0 && s2[t + 1] != s2[j])
{
t = next1[t];
}
if(s2[t + 1] == s2[j])
{
next1[j] = t + 1;
}
else
{
next1[j] = -1;
}
}
int i=0, j=0;
while(i < len1)
{
if(s1[i] == s2[j])
{
i++; j++;
if(j == len2)
{
cout<<i - len2 + 1<<endl;
j = next1[j-1] + 1;
}
}
else
{
if(j==0)
{
i++;
}
else{
j = next1[j-1] + 1;
}
}
}
for(int j = 0; j< len2; j++)
{
cout<< next1[j] + 1;
if(j == len2 - 1)
{
cout<<endl;
}
else
{
cout<<" ";
}
}
return 0;
}
算法练习3 POJ3416 Oulipo
http://poj.org/problem?id=3461
这道题比较尴尬,用string存字符串会显示Time Limit Exceeded,索性改成char数组才过的
#include <iostream>
#include<cstring>
#include<cstdio>
#include<string>
using namespace std;
#define MAXN 100005
int next1[MAXN];
char p[MAXN],s[MAXN*10];
void getNext(string p)
{
next1[0]= -1;
int t;
int len = p.size();
for(int j = 1; j < len; j++)
{
t = next1[j - 1];
while(t >= 0 && p[t + 1] != p[j])
{
t = next1[t];
}
if(p[t + 1] == p[j])
{
next1[j] = t + 1;
}
else
{
next1[j] = -1;
}
}
}
int kmp(string p, string s)
{
int lenp = p.size();
int lens = s.size();
int i = 0, j = 0;
int cnt = 0;
while(i < lens)
{
if(p[j] == s[i])
{
i++; j++;
if(j == lenp)
{
cnt++;
j = next1[j - 1] + 1;
}
}
else
{
if(j == 0)
{
i++;
}
else
{
j = next1[j - 1] + 1;
}
}
}
return cnt;
}
int main() {
// your code goes here
int T, cnt;
scanf("%d",&T);
while(T--)
{
scanf("%s%s",p,s);
getNext(p);
cnt = kmp(p,s);
printf("%d\n",cnt);
}
return 0;
}