简介
KMP算法相比于BF算法其最优点为,不用回退i,而且每次的j的回退根据next数组进行最优回退
代码
KMP
/**
* KMP核心算法
* @param str
* @param sub
* @return
*/
public static int KMP(String str,String sub)
{
//先判断是否符合规范
if(str.length()<sub.length())
{
return -1;
}
//机获得Next数组
int [] next = getNext(sub);
//sub下标位置
int j=0;
//str的下标位置
int i=0;
//直到i,j超出下标
while(i<str.length()&&j<sub.length())
{
//如果str和sub的当前元素相等,则i和j同时移动
//j=-1为,如果在匹配第一个失败的时候,进行回退会回退到-1位置,数组会越界,所以直接向后移动
if(j==-1||str.charAt(i)==sub.charAt(j))
{
i++;
j++;
}
//否则j根据next数组进行回退,i不回退
else
{
j = next[j];
}
}
//如果j大于sub数组,则说明查找成功了,返回第一个找到的第一个下标
if(j>=sub.length())
{
return i-j;
}//如果没找到,返回-1
else
{
return -1;
}
}
求Next
/**
* 求Next数组
* @param sub 要匹配的字符串
* @return Next数组
*/
public static int[] getNext(String sub)
{ //创建一个数组
int[] next = new int[sub.length()];
//初始化
next[0] = -1;
next[1] = 0;
//当前要求next的位置
int i = 2;
//k位置
int k =0;
//循环直到最后一个节点
while(i<sub.length()-1)
{
//如果k=-1或者两元素相等
if(k==-1||sub.charAt(k)==sub.charAt(i-1))
{
//当前的next大小等于前一个next+1
next[i++] = ++k;
}//如果不相等,进行回溯,寻找可以匹配的最小子串
else
{
k = next[k];
}
}
//返回next数组
return next;
}
KMP的分步匹配
i | j | 图解 | 执行操作 | 操作后i | 操作后j |
---|---|---|---|---|---|
0 | 0 | i++;j++ | 1 | 1 | |
1 | 1 | i++;j++ | 2 | 2 | |
2 | 2 | i++;j++ | 3 | 3 | |
3 | 3 | j=next[j] | 3 | 1 | |
3 | 1 | i++;j++ | 4 | 2 | |
4 | 2 | i++;j++ | 5 | 3 | |
5 | 3 | i++;j++ | 6 | 4 | |
6 | 4 | j为4超过循环范围,退出 | 退出 | 6 | 4 |
求Next数组的分步解释
题目为
abcabdca
答案为
-1,0,0,0,1,2,0,0
i | k | 图解 | 执行操作 | 操作后i | 操作后k | 操作后next数组 |
---|---|---|---|---|---|---|
2 | 0 | k=next[k] | 2 | -1 | -1,0 | |
2 | -1 | 判断为-1 | next[i++]=++k | 3 | 0 | -1,0,0 |
3 | 0 | k=next[k] | 3 | -1 | -1,0,0 | |
3 | -1 | 判断为-1 | next[i++]=++k | 4 | 0 | -1,0,0,0 |
4 | 0 | next[i++]=++k | 5 | 1 | -1,0,0,0,1 | |
5 | 1 | next[i++]=++k | 6 | 2 | -1,0,0,0,1,2 | |
6 | 2 | k=next[k] | 6 | 0 | -1,0,0,0,1,2 | |
6 | 0 | k=next[k] | 6 | -1 | -1,0,0,0,1,2 | |
6 | -1 | 判断为-1 | next[i++]=++k | 7 | 0 | -1,0,0,0,1,2,0 |
7 | 0 | k=next[k] | 7 | -1 | -1,0,0,0,1,2,0 | |
7 | -1 | 判断为-1 | next[i++]=++k | 7 | 0 | -1,0,0,0,1,2,0,0 |