您的位置:首页 > 其它

kmp总结及其应用

2013-04-28 20:41 183 查看
kmp含义

  克努斯-莫里斯-普拉特算法,一种字符串查找算法。

  字符串算法主要是用于主串 S( s1,s2,s3,...,sn ), 模式串T( t1,t2,...,tm ), 之间的匹配问题. 

  相对与模式匹配O(n^2)而言: 当 Si != Tj 失配时, 主串下标i不回溯, 而是将模式串下标j回溯到合适的地方,再继续比较 Tj ,Si.

时间复杂度极端情况是 O(N*M), 但是一般情况下总能保证O(N+M).

  假定串 S( i-j+1, i ) 与 模式串 T( 1, j ) 匹配时, Si != Tj 不匹配,此时需j最短回溯到 k,

  则存在 T(1,k-1) = T( j-k+1, j-1 ), 此时 k = next[j], 再令 Si 与 Tk 比较.

  则我们得出 next[] 的定义:

    next[i] = 0, 当 i = 0

    next[i] = Max{ k | 1 < k < j, 且 T(1,k-1) = T(j-k+1,j-1),当此集合不空时 }

    next[i] = 1, 其它情况.

int kmp( char *S, char *T ){ // 主串S,模式串T, 下标皆从1开始.
int la = strlen(S), lb = strlen(T);
int i = 1, j = 1;
while( i <= la && j <= lb ){
if( j == 0 || S[i] == T[j] ) i++, j++;
else    j = next[j]; //模式串向前滑动到 nxt[j]位置,继续比较
}
if( j > lb ) return i-j; //匹配成功,返回最初匹配点
return -1; //匹配失败
}


next数组

  next函数,表示对于模式串而言,其最长的前缀与后缀相同的长度.

  有定义知道 next[1] = 0;

  设 next[j] = k, 这表明在模式串中存在下列关系

    T( 1, k-1 ) = T( j-k+1, j-1 )

  此时 next[ j+1 ]的取值有两种情况:

    1. 当 T[k] == T[j] 时, 此时有 T( 1,k ) = T( j-k+1, j ), 则此时 next[ j+1 ] = next[j] + 1

    2. 但 T[k] == T[j] 时, 此时可把求 next函数值的问题看作是一个模式匹配的问题.整个模式串既是主串又是模式串.

按照前面主串与模式串匹配的思路, 则当 T[k] != T[j] 时, 应将模式串下标 k滑动到 next[k]时, 再与 T[j] 比较,

    最终可能出现两种情况:

        1. 匹配到, 此时 next[ j+1 ] = next[ k` ] + 1;

        2. 一直无法匹配则最后会得到, next[ j+1 ] = 1.

void GetNext( char *T, int *nxt ){
int len = strlen(T);
int i = 0, j = 1;
nxt[1] = 0;
while( j <= len ){
if( i == 0 || T[i] == T[j] )
nxt[ ++j ] = ++i;
else i = nxt[i];
}
}      


应用模型

  1. 模式串是否在主串中出现.

     poj 3080 Blue Jeans

    枚举其中一个串的主串,然后与其他串进行KMP匹配即可. 此题细节处理使用了STL.string.substr( 起点l, 数量num ).

View Code

#include<cstdio>
#include<cstring>
#include<cstdlib>
const int N = 400010;
char s
;
int res
, nxt
;

int main(){
while( scanf("%s", s) != EOF){
int len = strlen(s);
int i = 0, j = 1; nxt[1] = 0;
while( j <= len ){
if( i == 0 || s[i-1] == s[j-1] )
nxt[++j] = ++i;
else i = nxt[i];
}
int cnt = 0, x = nxt[len+1];
res[cnt++] = len;
while( x > 1 ) { res[cnt++] = x-1; x = nxt[x]; }
for(int i = cnt-1; i >= 0; i--)
printf( i == 0 ? "%d" : "%d ", res[i] ); puts("");
}
return 0;
}


  

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: