前言
PMT:PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度
Next数组:PMT向后移一位,最前位补-1。每个位置记录的则是前面的字符串的前缀集合与后缀集合的交集中最长元素的长度
代码
package newcoder;
/**
* KMP算法
*
*/
public class Kmp {
/**
* <P>构造next数组</P>
* <p> patternStr自己匹配自己得到next数组(自己的前缀匹配自己的后缀)
* @param patternStr 模式串
* @return 模式串的next数组
*/
public static int[] getNext(String patternStr) {
char[] strs = patternStr.toCharArray();
int[] next = new int[strs.length];
next[0] = -1; // 首位为-1,前面不存在匹配情况
int j = 0; // 用于遍历strs数组
int k = -1; // 匹配数量
while(j < strs.length-1) { // 下一位记录前面的,所以只遍历到到数第二位
if(k == -1 || strs[j] == strs[k]) {
if(strs[++j] == strs[++k]) {
// 优化部分:失配时,p[j]=p[next[j]],在这里直接令j=next[j],则主串少比对一次
next[j] = next[k];
} else {
// 下一位记录前面字符串的匹配长度
next[j] = k;
}
} else {
// 失配时,用模式串的前缀重合匹配串的后缀
// a b a b c d
// a b a b e 匹配到e时失败的,我的ab是匹配的,我们在e之前是自身匹配的,那么我可以认为你的ab也是自身匹配的,
// 我的前缀ab和你的后缀ab一定是相同的,没必要再比较
k = next[k];
}
}
return next;
}
public static boolean kmp(String str, String patternStr) {
char[] t = str.toCharArray();
char[] p = patternStr.toCharArray();
int i = 0, j = 0;
int[] next = getNext(patternStr);
while(i < t.length && j < p.length) {
if(j == -1 || t[i] == p[j]) {
// j = -1 时,完全失配,需要重新匹配,但此时i的位置还是在最后失配的位置上,需要+1
i++;
j++;
} else {
j = next[j];
}
}
if(j == p.length) {
return true;// 完全匹配上了
}
return false;
}
}