kmp:str1.indexOf(str2);
检查字符串2是1的子序列,并返回匹配的第一个字符位置
相比暴力匹配(时间复杂度O(N*M)),KMP通过nexts数组来加速匹配的过程,时间复杂度O(N)
next数组(建立的一个加速指标)
对str2,即要检查的字符串求next数组
nexts数组:i之前的字符串(和i本身无关)的前缀和后缀最大的匹配字符长度(不能取得整体,因为整体肯定是一样的,没有意义)
示例:nexts[]
a a x a a a a x a a x
0 1 2 3 4 5 6 7 8 9 10
-1 0 1 0 1 2 2 2 i
nexts[0]=-1 人为规定的
nexts[1]=0 不能取得整体所以是0
nexts[2]=1 a
nexts[3]=?怎么求?
看i-1位置的值是否等于y=next[i-1] y位置的值,
如果相等则nexts[i]=next[i-1]+1;
否则的话y=next[y]
当y=0时,则next[i]=0
加速匹配过程:
str1 a a b a a b k............
str2 a a b a a b a
i 0 1 2 3 4 5 6
next -1 0 3
nexts数组的用法:在遇到无法匹配的字符位置i(记为y)时,将str2[nexts[y]]=str1[i]
如果还是无法匹配时,将y重置为y=nexts[y] ->nexts[y],当nexts[y]=-1时,str2[0]==str1[i+1]
通过这种方式来加速匹配的过程
private static int getIndexOf(String str1,String str2){
if(str1==null||str2==null||str2.length()<1||str1.length()< str2.length()){
return -1;
}
int[] next=getNextArray(str2.toCharArray());
char[] ch1=str1.toCharArray();
char[] ch2=str2.toCharArray();
int x=0;//str1开始匹配的位置
int y=0;//str2开始匹配的位置
while (x<ch1.length&&y<ch2.length){//如果y越界,说明匹配成功,如果x越界,说明匹配结束了
if(ch1[x]==ch2[y]){
x++;
y++;
}else if(next[y]==-1){//y=0
//表示一通加速后,都没有匹配上,换个头重新开始匹配
x++;
}else{
y=next[y];
}
}
return y==ch2.length?x-y:-1;//如果y的长度等于str.length说明匹配成功,匹配开始位置为x-y
}
private static int[] getNextArray(char[] ms){
//如长度为1
if(ms.length==1){
return new int[]{-1};
}
//申请next数组
int[] next= new int[ms.length];
//o 位置为-1 人为规定
next[0]=-1;
//1位置为0,因为都不能取整体
next[1]=0;
//从位置2开始考虑
int i=2;
int y=0;//当前是哪个字符和i-1在比较
//处理位置没有越界
// nexts[i]=?怎么求?
// 看i-1位置的值是否等于y=next[i-1] y位置的值,
// 如果相等则nexts[i]=next[i-1]+1;
// 否则的话y=next[y]
while (i<next.length){
if(ms[i-1]==ms[y]){
next[i++]=++y;
}else if(y>0){
y=next[y];
}else {
next[i++]=0;
}
}
return next;
}