KMP:Knuth(D.E.Knuth)、Morris(J.H.Morris)和Pratt(V.R.Pratt)三人设计的线性时间字符串匹配算法。KMP算法是字符串匹配的经典算法。KMP算法是通过分析子串,预先计算每个位置发生不匹配的时候,直接移动到下一个”恰当“的位置。其中的关键是计算jump数组。(相关证明可以看算法导论二版32.4)
时间复杂度为O(n);
/*kmp相关ojhttp://www.cnblogs.com/wuyiqi/archive/2012/01/06/2315188.html*/
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int T=1000009;
const int W=10009;
/*在jump数组中,发现str[k+1]!=str[i]时,当前的最长proper后缀不能完全匹配字符串的前缀 ,
当前的后缀需要缩短后再尝试。
要求缩短后的后缀也要是字符串的一个前缀时,就意味着在str[i-k+x..i]中(x<=k,其实就是str[i-k..i]的proper后缀)
寻找一个x使得str[i-k..i]的后缀str[i-k+x..i]为整个字符串的一个前缀。
由于str[i-k..i]与str[1..k]完全匹配,问题就转化成了求str[1...k]的最长proper后缀为字符串前缀,也就是jump[k]。*/
void getp(const char *str,int len,int *&jump){//string from the index of 1
jump=new int[len+1];//is the proper suffix str' length for longest prefix
jump[1]=0;//
int k=0;
for(int i=2;i<=len;i++){
while(k>0&&str[k+1]!=str[i])
k=jump[k];//if this suffix it not the prefix,decrease suffix size
if(str[k+1]==str[i])
k=k+1;
jump[i]=k;
}
}
int kmp(const char *s,const char *t){//string from the index of 1
if(s==NULL||t==NULL)
return 0;
int len_s=strlen(s+1);
int len_t=strlen(t+1);
int *jump,i,count=0;
int j=0;//number of charachers matched
getp(s,len_s,jump);
for(i=1;i<=len_t;i++){
while(j>0&&s[1+j]!=t[i])
j=jump[j];//next character does not match, decrease match number to jump[j]
if(s[1+j]==t[i])
j++;//nes character matcheds,matched number ++
if(j==len_s){//is all of pattern matched?
count++;
j=jump[j];//look for the next match
}
}
return count;
}
int main(){
int n;
char w[W],t[T];
scanf("%d",&n);
while(n--){
scanf("%s%s",w+1,t+1);
int count=kmp(w,t);
printf("%d\n",count);
}
return 0;
}
例题:
KMP 的直接使用:http://poj.org/problem?id=3461
参考: