KMP算法,全称为Knuth-Morris-Pratt算法,是一种高效的字符串匹配算法,由Donald Knuth、Vaughan Morris和Robert Pratt三位学者提出。它的主要目标是在一个长字符串(主串A)中查找是否存在一个指定的短字符串(模式串B),如果存在,找出其在主串中的起始位置。KMP算法特别之处在于它可以避免不必要的字符比较,从而在最坏的情况下达到线性时间复杂度O(n),其中n为主串A的长度。
在传统的朴素字符串匹配算法中,当主串与模式串比较到某个位置不匹配时,需要从主串的下一个位置重新开始与模式串的首字符比较,这样效率较低。而KMP算法通过预处理模式串,构建一个“部分匹配表”(也称作“next数组”),可以得知在出现不匹配时,模式串无需回溯太多,而是可以直接将指针移动到一个已知的匹配位置继续进行比较。
以给定的例子A="abababaababacb"和B="ababacb"为例,KMP算法的工作过程如下:
初始时,i和j分别指向A和B的首字符,逐步比较A[i]和B[j]。当i=j=5时,A[6]≠B[6],此时需要调整j的值。根据部分匹配表,我们知道B[1..3]="abab"与B[4..6]="baba"相同,所以j可以从5降为3,使得A[6]与B[4]匹配,然后继续比较,i变为6,j变为4。
部分匹配表P[j]的计算是KMP算法的核心。对于模式串B,我们遍历B的每一个位置j,寻找最长的前后相同的子串,即找到最大的k使得B[1..k]与B[j-k+1..j]相等,这个k值就是P[j]。这样,当出现不匹配时,我们可以直接将j设为P[j],继续进行比较。
在实际应用KMP算法时,首先计算出模式串B的P[j]数组,然后进行字符串匹配。在匹配过程中,如果A[i]和B[j]匹配,则i和j都加1;如果不匹配,j根据P[j]回溯,i不变,直到找到匹配的下一个位置或j回溯到0。
KMP算法通过预先计算部分匹配表,避免了不必要的字符比较,提高了字符串匹配的效率。对于需要频繁进行字符串查找的应用场景,KMP算法具有显著的优势。虽然还有其他如Boyer-Moore和Sunday等字符串匹配算法,但KMP因其简洁和高效而被广泛使用和学习。