字符串匹配算法 - KMP算法

KMP算法简介

KMP算法(Knuth-Morris-Pratt算法)是一种常见的字符串匹配算法,用于在一个字符串中查找另一个字符串出现的位置。其时间复杂度为O(m+n),其中m为目标串的长度,n为模式串的长度。

在传统的字符串匹配算法中,一般情况下需要将目标串和模式串的每一个字符都逐一比较,这样的时间复杂度为O(m*n),效率较低。而KMP算法通过利用模式串内部的信息,来避免不必要的比较,从而提高效率。

KMP算法步骤

KMP算法的关键是求出模式串的失配函数,该函数的实现需要使用到动态规划。具体来说,以模式串"ABABCABD"为例,其失配函数的求解过程如下:

首先,设置一个长度为模式串长度的数组next,其中next[0]=-1。接着,从第二个字符开始逐一计算next数组的值。首先将next[1]的值赋为0,因为无论目标串中的字符与模式串第一个字符是否匹配,都只能将目标串向后移动一位。

接着,计算next[2]的值。假设已知next[1]的值为0,如果目标串中的字符与模式串第二个字符不匹配,那么模式串应该向后移动1个位置,也就是说,模式串的前缀"AB"和后缀"A"不相等,因此令next[2]=0。如果目标串中的字符与模式串第二个字符匹配,那么模式串应该向后移动2个位置,即next[2]=1。

以此类推,直到计算到next[8]的值(注意,虽然模式串有9个字符,但数组下标从0开始,因此下标最大值为8)。最终得到的next数组为:[-1,0,0,1,0,1,2,0]。其中,next[i]表示当模式串的第i个字符与目标串的某个字符失配时,模式串应该移动的位置。

接下来,以目标串"ABCABABCABABD"和模式串"ABABCABD"为例,介绍KMP算法的具体匹配过程。

首先,将目标串和模式串的第一个字符进行比较,发现匹配,因此继续比较第二个字符。此时,目标串的第二个字符为"B",而模式串的第二个字符为"A",因此发生了失配,根据失配函数的值,可以得知模式串应该向后移动1个位置。

接着,将模式串整体向后移动1个位置,然后再将目标串中的第三个字符和模式串中的第二个字符进行比较,发现匹配。接着比较目标串中的第四个字符和模式串中的第三个字符,发现匹配。以此类推,直到匹配到目标串中的第九个字符和模式串一一对应时,再次发生失配。

根据失配函数的值,可以得知模式串应该向后移动2个位置,于是将模式串整体向后移动2个位置,继续和目标串比较。以此类推,直到找到完全匹配的子串,或者目标串被匹配完为止。

总体来说,KMP算法通过建立失配函数来避免无用的比较,从而提高字符串匹配的效率。虽然该算法的实现较为复杂,但它对于大规模文本字符串的匹配具有显著的优势,是一种比较经典的字符串匹配算法。

KMP算法实现

下面是Java语言的KMP算法实现:

public class KMP {
    
    
    public int[] getPrefixTable(char[] pattern) {
    
    
        int[] table = new int[pattern.length];
        int index = 0;
        for (int i = 1; i < pattern.length; ) {
    
    
            if (pattern[i] == pattern[index]) {
    
    
                table[i] = ++index;
                i++;
            } else {
    
    
                if (index > 0) {
    
    
                    index = table[index-1];
                } else {
    
    
                    index = 0;
                    i++;
                }
            }
        }
        return table;
    }

    public int search(char[] text, char[] pattern) {
    
    
        int[] prefixTable = getPrefixTable(pattern);
        int i = 0;
        int j = 0;
        while (i < text.length && j < pattern.length) {
    
    
            if (text[i] == pattern[j]) {
    
    
                i++;
                j++;
            } else {
    
    
                if (j > 0) {
    
    
                    j = prefixTable[j-1];
                } else {
    
    
                    i++;
                }
            }
        }
        if (j == pattern.length) {
    
    
            return i - j;
        } else {
    
    
            return -1;
        }
    }
}

以上是KMP算法的完整实现,其中getPrefixTable方法用于生成模式串的前缀表(也称为部分匹配表),search方法用于在文本串中查找模式串的位置。

猜你喜欢

转载自blog.csdn.net/weixin_44008788/article/details/129659089