KMP算法
如何在一个字符串中找到是否含有某个子串呢?
最暴力的每次暴力,但是效率太低了,这个时候就引入了KMP算法了。
引入两个概念
- 前缀:指的是字符串中从原串前面开始的子串,如
abcde
的前缀有:a ab abc abcd abcde
- 后缀:指的是字符串的子串中在原串结尾处结尾的子串,如
abcdef
的后缀有:f,ef,def,cdef,bcdef
KMP算法引入了一个 next
数组, next[i]
表示的是前 i 个字符组成的这个子串 最长的相同前后缀的长度
KMP难就难在怎么计算这个 next
数组
package string;
import java.util.Arrays;
/**
* Class KMP ...
*
* @author LiJun
* Created on 2019/4/12
*/
public class KMP {
private int[] next;
/**
* 在这里我们需要匹配的是 t 串中的 s的下标
*
* @param s 母串
* @param p 子串
* @return 索引
*/
public int KMP_Index(String s, String p) {
int i = 0;
int j = 0;
initNextVal(p);
System.out.println(Arrays.toString(next));
char[] source = s.toCharArray();
char[] target = p.toCharArray();
while (i < source.length && j < target.length){
if(j == -1 || source[i] == target[j]){
++i;++j;
}else {
j = next[j];
}
}
if(j == target.length){
return i-j;
}
return -1;
}
/**
* 计算 next 数组
* @param t 传入值
*/
private void initNext(String t) {
next = new int[t.length()];
int i = 0, k = -1;
next[0] = -1;
char[] str = t.toCharArray();
while (i < t.length() - 1) {
if (k == -1 || str[i] == str[k]) {
++k;
++i;
}else{
k = next[k];
}
}
}
private void initNextVal(String t) {
next = new int[t.length()];
int i = 0, k = -1;
next[0] = -1;
char[] str = t.toCharArray();
while (i < t.length() - 1) {
if (k == -1 || str[i] == str[k]) {
++k;
++i;
if(str[i] != str[k]) {
next[i] = k;
} else {
next[i] = next[k];
}
}else{
k = next[k];
}
}
}
public static void main(String[] args) {
KMP kmp = new KMP();
System.out.println(kmp.KMP_Index("ababaaabtaababaaaba", "ababaaaba"));
}
}