首页 > 代码库 > EX_KMP算法总结

EX_KMP算法总结

EX_KMP算法总结

By viv

2014-8-9 0:30

吐槽1:字符串神马的我最讨厌了,但不学不行啊。TAT

吐槽2:写这东西差点错过CF(codeforces).

今天学了ex_kmp,故总结一下。(记性不好,学了的东西,说不定过两天就忘了)

先说说ex_kmp算法求得什么:

给定字符串T,P, n = |T| , m = |P|,定义ex[i] = T[i …n]和P的最长公共前缀的长度。

这就是ex_kmp问题,ex_kmp算法就死在线性时间内求得所有的ex[i]。

我们可以发现,如果ex[i] = m,则P在T中出现过,且位置为i,这正是KMP所求得东西。由此可见ex_kmp算法是对kmp的扩展。

下面说一下ex_kmp算法的流程(下表从0开始,当前节点为k,设P自己进行ex_kmp得到的ex数组为f数组):

假设ex[0,k)已经求好,在匹配中,到达的最远距离为p,即p为i + ex[i]的最大值,我们设取最大值的i为a。

这样我们可以得到以下几个关系:

T[a,p] = P[0,p - a]

T[k,p] = P[k – a,p - a]

这样,我们可以分两种情况:(用mspaint画的,很丑,字母大小写问题也不要在意了,明白就行)

情况1:

clip_image002

如上图,如果 K + f[k - a] < p的话,显然,图中灰色部分一定相同,蓝色部分一定不同。这样一来,f[k] = f[k - a] 且 a , p 的值不变。

情况2:

clip_image004

如上图,如果K+f[k - a] >= p的话,则,图中蓝色部分相同,紫色部分未知。这种情况下,我们就可以直接从p+1位开始匹配,直到失配。然后更新a , p的值。

就这样,整个算法已经完结了。至于f数组,自己和自己匹配一下就可以啦。

ex_kmp模板:

void getFail(char *T){    int idx = 0, mx = 0,n = strlen(T);    f[0] = n;    for (int i = 1; i < n; i++)    {        if (mx > i + f[i - idx])        {            f[i] = f[i - idx];            continue;        }        f[i] = max(mx - i, 0);        while (T[i + f[i]] == T[f[i]])            f[i]++;        if (i + f[i] > mx)            mx = i + f[i], idx = i;    }}void ex_kmp(char *T, char *P){    getFail(P);    int idx = 0, mx = 0,n = strlen(T);    for (int i = 0; i < n; i ++)    {        if (mx > i + f[i - idx])        {            ex[i] = ex[i - idx];            continue;        }        ex[i] = max(mx - i, 0);        while ((i + ex[i] < n) && T[i + ex[i]] == P[ex[i]])            ex[i]++;        if (i + ex[i] > mx)            mx = i + ex[i], idx = i;    }}

 

 

END