前言
本篇博客主要记录数据结构之KMP算法,通过举例来说明暴力匹配和KMP的不同。
一、问题解析
举个例子,如果给定文本串S“BBC ABCDAB ABCDABCDABDE”,和模式串P“ABCDABD”,现在要拿模式串P去跟文本串S匹配。
现将两种思路分析如下:
(1)暴力匹配
(2)KMP算法思路
二、代码测试
1.暴力破解
代码如下(示例):
/**
* 暴力匹配算法
* @param str1 原字符串
* @param str2 要匹配的字符串
* @return 思路:
* 1.如果当前字符匹配成功,则i++,j++,继续匹配下一个字符
* 2.如果匹配失败,令 i = i-(j-1),j=0 相当于每次匹配失败时,i回溯,j被置为0
*/
public static int violenceMatch(String str1, String str2) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int s1Len = s1.length;
int s2Len = s2.length;
//索引i指向s1
int i = 0;
//索引j指向s2
int j = 0;
while (i < s1Len && j < s2Len) {
if (s1[i] == s2[j]) {
//匹配成功
i++;
j++;
} else {
//匹配不成功
//如果匹配失败(s1[i]!=s2[j].令i=i-(j-1),j=0)
i = i - (j - 1);
j = 0;
}
}
//判断是否匹配成功
if (j == s2Len) {
return i - j;
} else {
return -1;
}
}
2.KMP代码
代码如下(示例):
使用KMP算法需要先得到字符串的匹配值表,代码中为next数组。具体求法如下图:
步骤:
1.先得到字符子串的部分匹配表;
2.使用部分匹配表完成KMP匹配。
/**
* 获取到一个字符串的部分匹配值
*/
public static int[] kmpNext(String dest) {
//创建next数组,保存部分匹配值
int[] next = new int[dest.length()];
//如果字符串长度为1,那么部分匹配值就是0
next[0] = 0;
for (int i = 1, j = 0; i < dest.length(); i++) {
//当dest.charAt(i) != dest.charAt(j),我们需要从next[j-1]获取新的j
//直到满足dest.charAt(i) == dest.charAt(j)才退出。
//这是temp算法的一个核心点
while (j > 0 && dest.charAt(i) != dest.charAt(j)) {
j = next[j - 1];
}
//当dest.charAt(i) == dest.charAt(j)条件满足时,部分匹配值就需要加一,放入数组
if (dest.charAt(i) == dest.charAt(j)) {
j++;
}
next[i] = j;
}
return next;
}
/**
* KMP搜索算法
* 没有匹配到就返回-1,匹配到就返回第一个匹配的位置
*/
public static int KMPSearch(String str1, String str2, int[] next) {
//遍历str1
for (int i = 0, j = 0; i < str1.length(); i++) {
//需要考虑str1.charAt(i)!=str2.charAt(j)的情况,需要调整j的值
while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
j = next[j - 1];
}
if (str1.charAt(i) == str2.charAt(j)) {
j++;
}
if (j == str2.length()) {
return i - j + 1;
}
}
return -1;
}