public class kmp {
/*
* KMP算法匹配字符串
*
*
*
* 前缀:必须包括首字符不包括尾字符的所有字符串
* 后缀:必须包括尾字符不包括首字符的所有字符串
* 部分匹配值:寻找前缀和后缀的最大共有字符串的长度(K值)
* 部分匹配的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度
* )。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。
*
*/
/**
* 求next值
* @param strs
* @return
寻找字符串每一位的部分匹配值,由于前一位字符串的最大共有字符串长度(部分匹配值K)已经知道了,
既strs[0]--strs[k-1]==strs[length-2-k]..strs[length-2]。
所以我们的工作是比较K+1位字符和当前位置是否相等(strs[k] ?= strs[length-1]),例如:
_______________________________
next[] 2 5
a b c a b a b a b c a b d
| | | | | | | | | |
a b c a b = a b c a b
a ?= d
______________________________
长度为length-1的字符串的部分匹配值为5(next[11]=5)
所以当需要匹配下一位的字符串的部分匹配值时,因为前面字符串的匹配值为5,我们只需比较5+1的字符和最后一位字符,既比较第6位和最后一位是否相等。
如果不相等,查找前一位的第二大相同字符串,由于前缀和后缀的特性,第二大相同字符串必定在两个abcab里面。所以我们只需求出abcab的最大相同字符串。
而abcab的最大相同字符串长度我们已经算出(next[4]=2)
所以我们现在只要比较最后一位和2+1的字符是否相等,如果不相等,重复上一步操作,直到部分匹配值为0,公式如下:
strs[length-1] ?=strs[k]
if(strs[length-1]!=strs[k] )
k = next[k-1]
strs[length-1] ?=strs[k]
if(==) k++;
*/
public int[] sortSon(char[] strs) {
int length = strs.length;
int[] next = new int[length];
int k = 0; // next值
next[0] = k;
for (int i = 1; i < length; i++) {
while (k != 0 && strs[i] != strs[k]) {
k = next[k - 1];
}
if (strs[i] == strs[k]) {
k++;
}
next[i] = k;
}
return next;
}
/**
* 查找出匹配字符串的首字母下标,步骤和求next值差不多
* 匹配失败时,根据所求的next值移动位置
* @param father
* @param son
* @return
*/
public int kmp( char father[],char son[])
{
int fatherLength,sonLength;
fatherLength = father.length;
sonLength = son.length;
int[] next = sortSon(son);
int k = 0;
for (int i = 0; i < fatherLength; i++)
{
while(k> 0 && father[i] != son[k]){
k = next[k-1];
}
if(i-k+sonLength>fatherLength){ //判断匹配的长度是否越界
return -1;
}
if (father[i] ==son[k])
{
k++;
}
if (k == sonLength)
{
return i-sonLength+1;
}
}
return -1;
}
public void test(){
char[] father = "eeeabcdfe".toCharArray();
char[] son = "abcdef".toCharArray();;
char[] father2 = "abeabcdef".toCharArray();
char[] son2 = "abcdef".toCharArray();;
// kmp(father, son);
Log.e("kmp", "匹配的下标为:"+kmp(father, son));
Log.e("kmp", "匹配的下标为:"+kmp(father2, son2));
}
}