解决对象:给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题。
1 暴力求解法:
暴力匹配的时间复杂度为 O(nm),其中 n 为 S 的长度,m 为 P 的长度。很明显,这样的时间复杂度很难满足我们的需求。
代码:
int naiveStringSearch(string S, string P){
int i = 0,j = 0;
int lens = S.length(),lenp = P.length();
while(i<lens&&j<lenp){
if(S[i]==P[j]){
i++;
j++;
}else{
i = i-j+1;
j = 0;
}
}
if(j==lenp){
return i-j;
}
return -1;
}
2 kmp求解:
假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j – next [j] 位。”
我们发现如果某个字符匹配成功,模式串首字符的位置保持不动,仅仅是i++、j++;如果匹配失配,i 不变(即 i 不回溯),模式串会跳过匹配过的next [j]个字符。整个算法最坏的情况是,当模式串首字符位于i – j的位置时才匹配成功,算法结束。
所以,如果文本串的长度为n,模式串的长度为m,那么匹配过程的时间复杂度为O(n),算上计算next的O(m)时间,KMP的整体时间复杂度为O(m + n)。
代码:
void next(string p,int a[]){ //模式串next化
int lenp = p.length();
a[0] = -1;
int i = 0,j = -1;
while(i<lenp){
if(j==-1||p[i]==p[j]){
i++;
j++;
a[i] = j;
}else{
j = a[j];
}
}
}
int kmp(string s,string p,int b[]){
next(p,b); //模式串next化
int i = 0,j = 0;
int lens = s.length(),lenp = p.length();
while(i<lens&&j<lenp){
if(j==-1||s[i]==p[j]){
i++;
j++;
}else{
j = b[j]; //匹配不成功,跳转
}
}
if(j==lenp){ //匹配成功
return i-j;
}
return -1;
}
完整代码:
/**
@字符串匹配-kmp算法
*/
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
/*普通算法
int naiveStringSearch(string S, string P){
int i = 0,j = 0;
int lens = S.length(),lenp = P.length();
while(i<lens&&j<lenp){
if(S[i]==P[j]){
i++;
j++;
}else{
i = i-j+1;
j = 0;
}
}
if(j==lenp){
return i-j;
}
return -1;
}*/
void next(string p,int a[]){ //模式串next化
int lenp = p.length();
a[0] = -1;
int i = 0,j = -1;
while(i<lenp){
if(j==-1||p[i]==p[j]){
i++;
j++;
a[i] = j;
}else{
j = a[j];
}
}
}
int kmp(string s,string p,int b[]){
next(p,b); //模式串next化
int i = 0,j = 0;
int lens = s.length(),lenp = p.length();
while(i<lens&&j<lenp){
if(j==-1||s[i]==p[j]){
i++;
j++;
}else{
j = b[j]; //匹配不成功,跳转
}
}
if(j==lenp){ //匹配成功
return i-j;
}
return -1;
}
int main(){
string s,p;
cin>>s>>p;
int a[20] = {0};
if(kmp(s,p,a)!=-1){
cout<<"匹配位置下标为:"<<kmp(s,p,a)<<endl;
}else{
cout<<"匹配失败"<<endl;
}
}
/*
bbcabcdababcdabcdabde
abcdabd
*/
- 结果: