扩展kmp基础问题:求子串T在母串S的最大前缀匹配,即字符串S[i...lenS-1](i=0...lenS-1)和字符串T的最大前缀匹配。
kmp和扩展kmp的辨析:当扩展kmp问题的最大前缀匹配数为lenT的时候,就是kmp的判断子串T是否在母串S中出现的问题,因此求最大公共前缀问题是kmp问题的扩展
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std ;
const int maxn = 1e5 * 2 + 19 ;
char x[maxn] , y[maxn] ;
int nxt[maxn] , ext[maxn] ;
void preekmp(char* x , int m , int* nxt){
nxt[0] = m ;
int j = 0 ;
while(j+1<m && x[j] == x[j+1]) j++ ;
nxt[1] = j ;
int k =1 ;
for(int i = 2 ;i<m ;i++){
int p = k + nxt[k] -1 ;
int l = nxt[ i - k ] ;
if( i + l < p +1) nxt[i] = l ;
else{
j = max(0 , p-i + 1) ;
while( i+ j <m &&x[i+j] == x[j]) j ++;
nxt[i] = j;
k = i ;
}
}
}
void ekmp(char* x , int m , char* y , int n , int* nxt , int* ext){
int j = 0 ;
while(j<n && j<m &&y[j] == x[j]) j ++ ;
ext[0] = j ;
int k = 0 ;
for(int i =1 ;i<n ;i++){
int p= k + ext[k] -1 ;
int l = nxt[i-k] ;
if(i + l < p+ 1) ext[i] = l ;
else{
j = max(0 , p-i +1) ;
while(i+j < n && j<m && y[i+j] == x[j]) j++ ;
ext[i] = j ;
k = i ;
}
}
}
void display(){
int len = strlen(y) ;
for(int i = 0 ;i< len ;i++){
cout<<y[i];
}
cout<<endl;
}
void print(){
int len = strlen(x) ;
for(int i = 0 ; i<=len ;i++){
cout<<nxt[i]<<" " ;
}
cout<<endl;
}
void prekmp(char* x , int m , int* nxt){
int i = 0 , j = -1 ;
nxt[0] = -1 ;
while( i < m){
while(j != -1 && x[i]!=x[j] ) j =nxt[j] ;
nxt[++i] = ++j ;
}
}
int main(){
int a ;
cin>>a ;
getchar() ;
for(int i = 1 ;i<= a ;i++){
gets(x) ;
memcpy(y , x , sizeof(x)) ;
strcat(y,x) ;
preekmp(x , strlen(x ) , nxt) ;
ekmp( x , strlen(x) , y , strlen(y) , nxt , ext ) ;
int lw = 0, eq= 0 , up= 0 ;
int lenx = strlen(x) ;
int leny = strlen(y) ;
for(int j = 0 ;j<lenx ; j++){
if( ext[j] >= lenx) eq ++;
else {
if(y[ j + ext[j] ] < x[ext[j]])
lw ++ ;
else
up++ ;
}
}
prekmp(x , strlen(x) , nxt) ;
int cyclic = 1 ;
if(lenx % ( lenx - nxt[lenx]) == 0 ){
cyclic = lenx / (lenx - nxt[lenx]) ;
}
printf("Case %d: %d %d %d\n", i , lw /cyclic , eq / cyclic,up/ cyclic) ;
}
return 0 ;
}