KMP 和 AC 自动机(坑)

KMP 和 AC 自动机(xyy版本)

xyynb!

KMP这里,字符串从1开始计数

KMP

众所周知,KMP是一种单串匹配算法,把朴素算法的O(|S|*|T|)优化到了O(|S|+|T|)
KMP 和 AC 自动机(坑)_第1张图片
如上图,在进行朴素算法时,如果我们已经进行了一些匹配成功,实际上我们就知道了原串的一些信息,理论上就可以使用这个信息来加速匹配,跳过一些绝对不可能匹配成功的情况。
所以,该怎么做呢?这就是KMP很迷的地方之一,也是我一直看不懂KMP的一个点。

border:最长相等前后缀

为此,xyy提到了border的概念。border即是某个字符串的最长相等前后缀(不包含自己)。
有了这个定义,再结合上面的图,就可以看到,如果在某个字符失配了,说明这个字符前的模式串T和字符串S是相等的,由于border的存在,可以直接跳过一些字符串,直接跳到失配字符前的模式串T的border,比较border之后的字符。
一定没有错过什么能够正确匹配的情况吗?是的,反证可以证明,要是存在,那border就不是最长了。
也就是说,KMP分为两个步骤,求T中每个字符前的子串对应的border长度,然后匹配。一般把前者(每个字符前的子串对应的border的长度)定义为fail[]数组,或者xyyπ()函数

fail[]数组

在T也很长的时候,暴力求解fail[]数组也是不可取的。
在这里插入图片描述
这种情况下,可以看出:

由于π(3)=1,可得T[1...1]==T[3...3]
又由于T[2]==T[4]T[1...2]==T[3...4]
所以π(4)=2=π(3)+1

综上,T[i+1]==T[π(i)+1],则π(i+1)=π(i)+1

那如果T[i+1]≠T[π(i)+1]呢?
border的border仍然是原串的border
有一个神奇的性质,borderborder仍然是原串的border

由于abacaba是原串的border,则黄串+c+绿串==蓝串+c+红串
由于abaabacababorder,则黄串==绿串,蓝串==红串
所以,黄串==绿串==蓝串==红串

因此,我们可以用递归的方法,如果T[i+1]≠T[π(i)+1],则检查T[i+1]==T[π(π(i))+1],以此类推,直至出现相等。如果真的很惨,一个border,那么应该递归到π(i)=0,这时,T[i+1]==0

综上,求fail[]数组的代码为:

void getFail()
{
	for (int i = 1; i < pl; i++)
	{
		int j = i-1;
		while (j > 0 && p[fail[j]+1] != p[i]) j = fail[j];
		fail[i] = j ? fail[j] + 1 : 0;
	}
	return;
}

匹配的过程

AC 自动机

你可能感兴趣的:(C++,字符串,坑)