KMP算法
KMP算法是用来做字符串匹配的,他以他的三个发明者命名,其效率非常高。
常见的字符串匹配算法
- BF(BruteForce)暴力匹配对主串和模式串进行逐个字符匹配,效率很低,每一轮只能将模式串右移一位。
- BM(Boyer-Moore)算法 核心试想是模式串中不存在的字符一定不匹配,后移
- KMP算法 核心在于部门匹配表(partial match table),本质也是减少冗余的字符比较
核心代码
获取部分匹配表
/**
* PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度
* 获取字符串的部分匹配表
*/
public static int[] getPartialMatchTable(String str) {
int[] table = new int[str.length()];
// 单个字符 部分匹配表一定是[0]
table[0] = 0;
for (int i = 1, j = 0; i < str.length(); i++) {
// 不匹配
while (j > 0 && str.charAt(i) != str.charAt(j)) {
j = table[j - 1];
}
if (str.charAt(i) == str.charAt(j)) {
// 如果匹配 部分匹配值+1
j++;
}
table[i] = j;
}
return table;
}
代码示例
public class KMPMatch {
public static void main(String[] args) {
String str1 = "BBC ABCDAB ABCDABCDABDE";
String str2 = "ABCDABD";
// System.out.println(Arrays.toString(getPartialMatchTable("ABCDABD")));
System.out.println(kmpMatch(str1, str2, getPartialMatchTable(str2)));
}
/**
* PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度
* 获取字符串的部分匹配表
*/
public static int[] getPartialMatchTable(String str) {
int[] table = new int[str.length()];
// 单个字符 部分匹配表一定是[0]
table[0] = 0;
for (int i = 1, j = 0; i < str.length(); i++) {
// 不匹配
while (j > 0 && str.charAt(i) != str.charAt(j)) {
j = table[j - 1];
}
if (str.charAt(i) == str.charAt(j)) {
// 如果匹配 部分匹配值+1
j++;
}
table[i] = j;
}
return table;
}
/**
* 移动位数 = 已匹配的字符数 - 对应的部分匹配值
*
* @param str1
* @param str2
* @return
*/
public static int kmpMatch(String str1, String str2, int[] pmt) {
for (int i = 0, j = 0; i < str1.length(); i++) {
while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
// 利用部分匹配表调整J的位置
j = pmt[j - 1];
}
if (str1.charAt(i) == str2.charAt(j)) {
j++;
}
if (j == str2.length()) {
return i - j+1;
}
}
return -1;
}
}
后附上阮一峰老师对部分匹配表的讲解非常的形象!
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html