概述
- KMP是一个解决模式串在文本串中是否出现过,如果出现过,获得最早出现的位置的经典算法(实现Java中的indexOf的功能)
- KMP算法利用遍历文本串时判断过的信息,通过一个next数组,保存模式串前后最长公共子序列的长度,每次回溯时,通过next数组找到前面匹配过的位置,省去了大量的计算时间
部分匹配值
部分匹配值就是前缀和后缀的最长共有元素长度
前缀:除了整个字符串以外,从头开始依次增加一个字符,如ABC的前缀表:{A,AB}
后缀:除了整个字符串意外,从尾开始依次增加一个字符,如ABC的后缀表:{C,BC}
部分匹配值的求解
/**
* 获取部分匹配值表
* @param s
* @return
*/
private static int[] kmpNext(String s) {
int []next = new int[s.length()];
// 在字符串长度为1的地方,前缀和后缀都是""所以,部分匹配值为0
next[0] = 0;
// 动态规划,已经初始化了长度为1的字符串的部分匹配值,从长度为2开始匹配
for(int i=1,j=0;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;
}
return next;
}
KMP搜索算法
/**
* kmp搜索
* @param s1 源字符串
* @param s2 子串
* @param next 子串的部分匹配表
* @return
*/
private static int kmpSearch(String s1,String s2,int []next) {
for(int i=0,j=0;i<s1.length();i++) {
// j不从0开始重新匹配,而是从前一个最长公共长度开始
while(j>0&&s1.charAt(i)!=s2.charAt(j)) {
j = next[j-1];
}
// 当前源字符串和子串是匹配的
if(s1.charAt(i)==s2.charAt(j)) {
j++;
}
// 已经找到完整的子串
if(j==s2.length()) {
return i-j+1;
}
}
return -1;
}