首页 > 代码库 > 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:
如上图,如果 K + f[k - a] < p的话,显然,图中灰色部分一定相同,蓝色部分一定不同。这样一来,f[k] = f[k - a] 且 a , p 的值不变。
情况2:
如上图,如果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