KMP是Knuth、Morris和Pratt首字母的缩写,KMP也是由这三位学者发明(1977年联合发表论文)。
KMP主要应用在字符串的匹配,是一个解决模式串在文本串是否出现过,如果出现过,得出最早出现的位置的经典算法。其主要思想是:当出现字符串不匹配时,可以知道之前已经匹配的文本内容,可以利用这些信息避免从头再去匹配,从而提高匹配效率。
因此如何记录已经匹配的文本内容,才是KMP的重点~这也使得next数组派上了用场。
KMP算法就利用之前判断过信息,通过一个 next 数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过 next 数组找到前面匹配过的位置,省去了大量的计算时间。
现给出一段字符串str1:“硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好”,和一段子字符串str2:“尚硅谷你”。
要求写出判断str1是否含有str2的代码,如果存在就返回第一次出现的位置,如果没有则返回-1。
说到字符串匹配,我们第一时间想到的是直接遍历字符串,看看是否存在。这种方法称为暴力匹配,抛开效率不说,这种方式是最直接,最简单的方式。
然而暴力匹配也是一种算法,一种解决方案,针对上述问题,我们可以得出暴力匹配算法的思路(假设现在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置):
代码示例:
/**
* 暴力匹配算法
* @param str1
* @param str2
* @return 返回str2首次出现在str1的位置,匹配不到则返回-1
*/
public static int violenceMatch(String str1, String str2) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int i = 0; // 指向s1
int j = 0; // 指向s2
while (i < s1.length && j < s2.length) {
if (s1[i] == s2[j]) {
i++;
j++;
} else {
// 只要有一个没有匹配上
i = i - (j - 1);
j = 0;
}
}
// 判断是否匹配成功
if (j == s2.length) {
return i - j;
}
return -1;
}
在main
方法中测试暴力匹配:
public class AlgorithmUtils {
public static void main(String[] args) {
String str1 = "硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好";
String str2 = "尚硅谷你";
int index = AlgorithmUtils.violenceMatch(str1, str2);
if (index != -1) {
System.out.printf("第一次出现的位置是%d", index);
}
}
}
前面呢我们已经使用暴力匹配算法,完成了上述问题的求解!也知道了暴力匹配存在效率问题,那么KMP算法又是怎样实现呢?
为方便阐述,这里我们换个案例:现有两组字符串
str1 = “BBC ABCDAB ABCDABCDABDE”;
str2 = “ABCDABD”;
要求使用 KMP算法 完成判断,str1 是否含有 str2,如果存在,就返回第一次出现的位置,如果没有,则返回-1。
备注:不能使用简单的暴力匹配算法!!!