KMP算法是一种高效的字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。它通过利用已经匹配过的字符信息,避免不必要的回溯操作,提高了匹配的效率。
KMP算法的核心思想是构建一个最大公共前后缀表(也称为部分匹配表),根据该表在匹配过程中确定模式串向后移动的位置。下面将详细介绍KMP算法的实现步骤和Java代码。
一、构建最大公共前后缀表
最大公共前后缀表是一个长度与模式串相等的数组,用于存储每个位置对应的最大公共前后缀长度。具体的构建方法如下:
1、初始化最大公共前后缀表为一个与模式串长度相同的数组,默认值都为0。
2、从第二个位置开始遍历模式串,依次计算每个位置对应的最大公共前后缀长度。
1)、假设当前位置为i,已知前i-1个位置的最大公共前后缀长度为prefixLen[i-1]。
2)、如果模式串的第prefixLen[i-1]个字符与模式串的第i个字符相等,则最大公共前后缀长度为prefixLen[i-1]+1。
3)、否则,继续往前查找长度为prefixLen[i-1]的最大公共前后缀,直到找到相等的字符或长度为0。
4)、更新prefixLen[i]为找到的最大公共前后缀的长度。
以下是使用Java代码实现构建最大公共前后缀表的函数:
private int[] buildPrefixTable(String pattern) {
int[] prefixLen = new int[pattern.length()];
prefixLen[0] = 0;
int len = 0;
int i = 1;
while (i < pattern.length()) {
if (pattern.charAt(i) == pattern.charAt(len)) {
len++;
prefixLen[i] = len;
i++;
} else {
if (len != 0) {
len = prefixLen[len - 1];
} else {
prefixLen[i] = 0;
i++;
}
}
}
return prefixLen;
}
二、KMP算法的匹配过程
KMP算法的匹配过程分为主串与模式串的对比和模式串的后移两个步骤。具体的实现如下:
1、初始化一个指针i指向主串的第一个位置,一个指针j指向模式串的第一个位置。
2、在匹配过程中,一直循环直到到达主串的末尾或找到了一个匹配的位置。
1)、如果主串的第i个字符与模式串的第j个字符相等,则同时将i和j都向后移动一位。
2)、如果j已经到达模式串的末尾,说明找到了一个匹配的位置,将该位置记录下来(可以是存储到一个List中或直接打印)。
3)、如果主串的第i个字符与模式串的第j个字符不相等:根据最大公共前后缀表,将模式串向右移动j - prefixLen[j-1]位。如果prefixLen[j-1]为0,则将模式串向右移动一位。注意:主串的指针i不需要回溯,继续与新的j进行对比。
以下是使用Java代码实现KMP算法的匹配过程:
public List kmpMatch(String text, String pattern) {
List positions = new ArrayList<>();
int n = text.length();
int m = pattern.length();
int[] prefixLen = buildPrefixTable(pattern);
int i = 0; // 主串指针
int j = 0; // 模式串指针
while (i < n) {
if (text.charAt(i) == pattern.charAt(j)) {
i++;
j++;
}
if (j == m) { // 找到一个匹配位置
positions.add(i - j);
j = prefixLen[j - 1];
} else if (i < n && text.charAt(i) != pattern.charAt(j)) {
if (j != 0) {
j = prefixLen[j - 1];
} else {
i++;
}
}
}
return positions;
}
三、KMP算法的应用举例
使用KMP算法,我们可以在一个主串中高效地查找一个模式串的出现位置。以下是一个简单的示例代码:
public static void main(String[] args) {
String text = "ABABDABACDABABCABAB";
String pattern = "ABABCABAB";
List positions = kmpMatch(text, pattern);
System.out.println("Pattern found at positions: " + positions);
}
输出结果为:Pattern found at positions: [10]
表示在主串text的位置10处找到了与模式串pattern相匹配的子串。
KMP算法的时间复杂度为O(n+m),其中n为主串的长度,m为模式串的长度。相对于简单的暴力匹配算法,KMP算法具有更高的效率和优化性能。