KMP&exKMP小结

前缀函数

\(p[i]\)表示即使字符串前缀\([1...p[i]]\)又是以\(i\)为结尾的后缀\([i-p[i]+1...i]\)
暴力为\(O(n^3)\)
我们可以发现:\(p[i+1]<=p[i]+1\)
接着暴力便可以优化了,成为\(O(n^2)\)
但我现在不知道怎样优化成\(O(n^2)\)
然后我们可以发现,当\(s[p[i]+1]!=s[i+1]\),我们要找到最大的\(k\)使得\([1...k]\)\([i-k+1...i]\)仍相等,然后在此比较下一个字符。
于是乎,\(KMP\)雏形已成,可以登场了。

什么是KMP

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。——百度百科

KMP

由于暴力匹配时间复杂度较高,所以考虑优化。
我们设\(nx[i]\)表达在第\(i\)位失配后跳到的位置。
我们保证\(s[1]\)$s[nx[i]]$与$s[i-nx[i]+1]$\(s[i]\)按位相同。

推荐阅读

Code 板子

#include <cstdio>
#define N 100010
#define mem(x, a) memset(x, a, sizeof x)
#define fo(x, a, b) for (int x = a; x <= b; x++)
#define fd(x, a, b) for (int x = a; x >= b; x--)
using namespace std;
int n, m, nx[N], ans = 0;
char s1[N], s2[N];

inline int read()
{
	int x = 0; char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return x;
}

int main()
{
	freopen("KMP.in", "r", stdin);
	freopen("KMP.out", "w", stdout);
	n = read(), m = read();
	scanf("%s\n%s", s1 + 1, s2 + 1);
	int j = 0; nx[1] = 0;
	fo(i, 2, m)
	{
		while (j && s2[j + 1] != s2[i]) j = nx[j];
		if (s2[j + 1] == s2[i]) j++;
		nx[i] = j;
	}
	j = 0;
	fo(i, 1, n)
	{
		while (j && s2[j + 1] != s1[i]) j = nx[j];
		if (s2[j + 1] == s1[i]) j++;
		if (j == m) printf("%d\n", i - j + 1), j = nx[j];
	}
	return 0;
}

什么是exKMP

由于没有百度百科,就贴个图片。

exKMP

不会,会了再更。

posted @ 2019-08-11 20:36  jz929  阅读(278)  评论(0编辑  收藏  举报