KMP是什么?
KMP算法是一种改进的字符串匹配算法,大大提高了字符串匹配的效率。至于为什么叫KMP,因为这个算法是由Knuth、Morris和Pratt三位大佬发明出来的,取大佬们名字的首字母组成了算法的名字。
KMP实现核心
KMP算法之所以高效是因为它减少了模式串与主串的匹配次数,这一切都归功于next数组。next数组本质上是一个前缀表,里面存放着神奇的东西,它记录着当匹配失败时需要回退的大小。
Brute-Force暴力求解
暴力解法的思想很简单,循环匹配,当匹配失败时返回到上一次开始匹配的下一个位置重新匹配。假设主串长度为m,模式串为n,暴力解法的时间复杂度为O(m*n)。
public static int bruteForce(String str1, String str2) {
int i = 0, j = 0;
while (i < str1.length() && j < str2.length()) {
if (str1.charAt(i) == str2.charAt(j)) {
i++;
j++;
} else {
i = i - j + 1; // 主串回到上一次的下一个位置
j = 0; // 模式串从头开始匹配
}
}
if (j == str2.length())
return (i - str2.length());
return -1;
}
KMP求解
next数组实现
/*
对于任何字符串来说,前缀表的第一个字符作为单个字符串,没有前缀。
前缀的表示有很多种,有的是将正常的下标统一左移,这里使用的是没有位移的原始坐标。
*/
public static void getNextArr(int[] next, String s) {
int j = 0;//j表示前缀起始位置
next[0] = 0;
//i表示后缀起始位置
for(int i = 1; i < s.length(); i++) {
while (j > 0 && s.charAt(i) != s.charAt(j)) {
j = next[j - 1];
}
if (s.charAt(i) == s.charAt(j)) {
j++;
}
next[i] = j;
}
}
KMP实现
public static int getIndexOf(String haystack, String needle) {
if (haystack == null){
return -1;
}
if (needle == null || needle.length() == 0) {
return -1;
}
int[] next = new int[needle.length()];
getNextArr(next, needle);
int j = 0;
for (int i = 0; i < haystack.length(); i++) {
while(j > 0 && haystack.charAt(i) != needle.charAt(j)) {
j = next[j - 1];
}
if (haystack.charAt(i) == needle.charAt(j)) {
j++;
}
if (j == needle.length() ) {
return (i - needle.length() + 1);
}
}
return -1;
}