KMP
处理字符串匹配,暴力枚举O(n*n)是很好写的,但是很多题目接受不了这样的时间复杂度,然后KMP算法诞生了。
举个例子先:
模式串:abb
匹配串:ababb
匹配到第三个字符时失配了,如果是暴力匹配这时我们又会用模式串的第一个a来匹配匹配串的第二个b,这显然是很多余的操作,因为不可能匹配成功。这样浪费了巨量的时间,KMP算法则是用O(n)的时间来处理一下模式串,从而使匹配更有效率。
那怎么匹配呢?
举个例子再:
模式串:abaab(我们将这个字符串由0~4标号)
我们设置一个fix数组,代表如果这一位失配了,将要跳到哪一位继续匹配。
第0个字符:如果第0位就失配了,那没有办法了,只能再从0开始匹配,fix[0]=0;
第1个字符:和第0位一样,如果失配就回到0,fix[1]=0;
第2个字符:如果这一位失配了怎么办呢?
abaab
baab
..↑it’s me
这样肯定不行
abaab
aab
↑it’s me
那只能这样了,fix[2]=0;
第3个字符:如果这一位失配了怎么办呢?
abaab
baab
…..↑it’s me
不行
abaab
aab
..↑it’s me
要是这么跳的话,前面的就一样了,那如果我失配了,就让匹配串跟这一位配吧。
fix[3]=1;
第四个字符:如……?
……
abaab
ab
..↑it’s me
fix[4]=1。
以上是思考过程,重点是,如果我失配了,我就往前跳,但要求我跳完之后和模式串的前缀相同。
具体怎么实现呢?
按照刚刚的思考方式,如果当前位置失配了怎么办呢?
先想想上一位失配了,那它就会往回跳,保证它前面的一部分是这个模式串的前缀,如果这时恰好它跳到位置和它正好相同,那当前位置就找到了失配时应该跳的位置。
我说的不清晰,可以参照代码理解(注意事项在代码后):
fix[0]=0; fix[1]=0;
for(int i=1;i<lenc;i++)
{
int j=fix[i];
while(j && c[j]!=c[i]) j=fix[j];
if(c[j]==c[i]) fix[i+1]=j+1;
else fix[i+1]=0;
}
注意事项:
1、上面的代码是用这一位来推下一位的状态,和之前写的可能不太相同,但是思想是一样的(c数组是模式串);
2、fix[0]和fix[1]最开始时就赋值为0;
3、如果j跳到0要结束循环(否则会死循环);
4、赋值时赋的是j的下一位。
KMP的模板很短也很好背,但是比较难理解,多写多想会好一些。
最后就是匹配了。
匹配就比较简单了,正常暴力匹配,但是失配时把模式串的指针往前跳继续与匹配串匹配就好了,当匹配成功的长度与模式串长度相同时,把答案+1就可以了。
匹配代码如下(s数组是匹配串,注意事项在代码后):
int j=0;
for(int i=0;i<lens;i++)
{
while(j && c[j]!=s[i]) j=f[j];
if(s[i]==c[j]) j++;
if(j==lenc) {ans++; j=0;}
}
注意事项:
1、j跳到0时要结束循环(理由同上);
2、当j==lenc的时候不一定要吧j赋值成0,这道题需要赋值成0,其他的题可能需要往前跳(当子串可以重复时)。
【HDU2087 剪花布条】
这是一道KMP练手裸题。
题目大意:
给定匹配串和模式串,问有匹配串中有多少个子串与模式串相同(子串不能重叠)。
题目分析:
KMP
代码:把上面两个拼起来就可以了。

本文深入讲解KMP算法的原理及应用,通过实例演示如何构造KMP的fix数组,并给出匹配过程的具体步骤。此外,还提供了代码实现细节及注意事项。

被折叠的 条评论
为什么被折叠?



