@Test
public void kmp(){
//得到子串的前缀和
String pattern = "ababcabaa";//001201231
char[] pattern2 = pattern.toCharArray();
// getPre(pattern2);
String text = "abababcabaababa";
char[] text2 = text.toCharArray();
search1(text2,pattern2);
}
private void search1(char[] text, char[] pattern) {
int[] pre = getPre(pattern);
pre = modify(pre);
int textlen = text.length;
int patternlen = pattern.length;
int te = 0,pa = 0;
//逐个开始遍历
while (te<textlen){
if (pa == patternlen-1 && pattern[pa] == text[te]){
//这时说明已经找到
System.out.println("found:"+(te-pa));
//然后继续回退,寻找下一个
pa = pre[pa];
}
//两个字符相等,则继续比较下一个字符
if (pattern[pa] == text[te]){
pa++;
te++;
}else {
//两个字符不相等,那么子串就会回退到上一个前缀和,继续比较
pa = pre[pa];
//回退到pa = -1,说明已经到头了,不能在往前了,于是整体+1
if (pa == -1){
pa++;
te++;
}
}
}
}
//修改前后缀表,那么index代表是(index-1)的前后缀和,方便回退
private int[] modify(int[] pre) {
int length = pre.length;
for (int i = length-1; i > 0 ; i--) {
pre[i] = pre[i-1];
}
pre[0] = -1;
return pre;
}
private int[] getPre(char[] pattern) {
int length = pattern.length;
//得到前后缀和表
int[] pre = new int[length];
pre[0] = 0;
//从1处开始比较
int index = 1;
//表示index-1的前缀和
int len = 0;
while (index<length){
//要比较的字符(index)等于(index-1)处的前缀和的字符
if (pattern[index] == pattern[len]){
//前缀和+1
len++;
//将前缀和记录在前缀和表中
pre[index] = len;
//index+1,继续比较一下一个字符
index++;
}else {
//要比较的字符(index)不等于(index-1)处的前缀和的字符
//就回退到上一个前缀和,再次进行比较
if (len>0){
len = pre[len-1];
}else {
//如果len = 0,且此处的前缀和还是不等于当前字符,
//那么就说明这个字符的前缀和为0,而且要开始比较下一个字符
pre[index] = len;
index++;
}
}
}
return pre;
// System.out.println(Arrays.toString(pre));
}
kmp算法
于 2022-09-01 21:31:34 首次发布