编程题之——KMP算法Java实现
有如下问题:有模式字符串mode=”acabaabaabcacaabc”,有个目标字符串target=”abaabcac”,现在要在遍历mode串,看target串是否是目标串的子串。下面用KMP(模式匹配算法)实现。在KMP中,最主要的元素就是next[]数组的实现了。
一、next[]数组实现
声明:本方法参考了《数据结构(c语言版)》的KMP算法以及网上的一些KMP算法,解题过程与《数据结构(c语言版)》的KMP算法略有不同
1、next值求解过程
如果target串中,前缀等于后缀,即:“
所以j=1时,next[0] = 0;当j=2时,属于其他情况,next[1]=1
当j=3时,j-1=2,串长为“ab”,则前缀取到k-1,后缀取到j-1:
k-1 | 前缀 | 关系 | 后缀 |
---|---|---|---|
1 | a | != | b |
属于“其他情况”,所以next[3] = 1;
当j=4时,j-1=3,串长为“aba”,则前缀取到k-1,后缀取到j-1:
k-1 | 前缀 | 关系 | 后缀 |
---|---|---|---|
1 | a | == | a |
2 | ab | != | ba |
在上表有前缀等于后缀的情况k-1=1,且没有其他前缀等于后缀时k值大于它的情况,所以k-1=1 =>k=2;next[4]=2;
当j=5时,j-1=4,串长为“abaa”,则前缀取到k-1,后缀取到j-1:
k-1 | 前缀 | 关系 | 后缀 |
---|---|---|---|
1 | a | == | a |
2 | ab | != | aa |
3 | aba | != | baa |
在上表有前缀等于后缀的情况k-1=1,且没有其他前缀等于后缀时k值大于它的情况,所以k-1=1 =>k=2;next[5]=2;
当j=6时,j-1=5,串长为“abaab”,则前缀取到k-1,后缀取到j-1:
k-1 | 前缀 | 关系 | 后缀 |
---|---|---|---|
1 | a | != | b |
2 | ab | == | ab |
3 | aba | != | aab |
4 | abaa | != | baab |
在上表有前缀等于后缀的情况k-1=2,且没有其他前缀等于后缀时k值大于它的情况,所以k-1=2 =>k=3;next[6]=3;
当j=7时,j-1=6,串长为“abaabc”,则前缀取到k-1,后缀取到j-1:
k-1 | 前缀 | 关系 | 后缀 |
---|---|---|---|
1 | a | != | c |
2 | ab | != | bc |
3 | aba | != | abc |
4 | abaa | != | aabc |
5 | abaab | != | baabc |
上述属于next取值的三种情况中的“其他情况”,所以next[7]=1;
当j=8时,j-1=7,串长为“abaabca”,则前缀取到k-1,后缀取到j-1:
k-1 | 前缀 | 关系 | 后缀 |
---|---|---|---|
1 | a | == | a |
2 | ab | != | ca |
3 | aba | != | bca |
4 | abaa | != | abca |
5 | abaab | != | aabca |
6 | abaabc | != | baabca |
在上表有前缀等于后缀的情况k-1=1,且没有其他前缀等于后缀时k值大于它的情况,所以k-1=1 =>k=2;next[8]=2;
总上所得,j与next[j]对应表如下:
j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
target | a | b | a | a | b | c | a | c |
next[j] | 0 | 1 | 1 | 2 | 2 | 3 | 1 | 2 |
代码实现求next值
public static void getNext(String str,int next[]){
int j = 1;
next[1] = 0;
next[2] = 1;
int max = 0;
for(j=3;j<=str.length();j++){
max = 0;
for(int k=2;k<j;k++){
if(str.substring(0, k-1).equals(str.substring(j-k, j-1))){
if(k>max)
max = k;
}
}
if(max == 0)
next[j]=1;
else
next[j] = max;
}
}
KMP函数为:
public static void kmp(String mode,String target,int[]next){
int j = 1;
int i;
for(i=1;i<=mode.length()&&j<=target.length();){
if(j==0){
i++;
j++;
}else{
if(mode.charAt(i-1)==target.charAt(j-1)){
i++;
j++;
}else{
j = next[j];
}
}
}
if(j>target.length()){//输出匹配成功的子串
System.out.println(mode.substring(i-j, i-1));
}
}