KMP算法的理解

学了一天终于了解KMP算法了,下面我通过图片讲解一下。

 先说一下Bru-Force算法,比如我们要从序列:

1 2 3 1 2 3 1 2 3 1 2 3 4中寻找序列1 2  3 1 2 3 4我们可以进行如下操作:

KMP算法的理解_第1张图片

KMP算法的理解_第2张图片

 

KMP算法的理解_第3张图片

。。。。。。

KMP算法的理解_第4张图片

就这样一步一步可以类推出来子序列在目标串中的位置,但是这种效率如果碰到特殊情况如:目标串为:aaaaaaaaab,目标串:aaab的情况,算法的复杂度就会落到O(n*m),其中n*m分别为目标串和子序列的长度。

而KMP算法可以对这个问题进行优化,下面我们解释KMP算法。

说到KMP算法,首先要说的就是NEXT数组,我们先求出子序列 1 2 3 1 2 3 4的NEXT数组:

KMP算法的理解_第5张图片

我们先不说这个表是怎么来的,我们先看看这东西怎么用,一会再说这个东西怎么求。

先看第一次遍历:

KMP算法的理解_第6张图片

我们发现这个4这个的位置和1不相等,然后我们看一下,4的next数组对应值是3。然后我们就可以直接用子序列下标为3的地方和目标串与子序列不相等那个1比较(注意一点就是如果next数组是-1的话,那子序列从头开始比较,目标串比较位置右移一位),就是打星星的地方:

KMP算法的理解_第7张图片

发现依然是这个4和那个1不相等,方法同上:

然后我们就能求得这个问题的最终结果,这样打打减少了比较的次数。

那么这个目标串什么求呢?

要弄懂这个先要清楚前后缀。

我还以1 2 3 1 2 3 4为例子,

其中1没有前后缀。

1 2:前缀:{1};后缀:{2}。

1 2 3:前缀{1,1  2};后缀{3, 2  3}。

1 2 3 1:前缀{1,1  2,1  2  3};后缀{1,3  1;2  3  1}。

1 2 3 1 2:前缀{1,1  2,1  2  3,1 2 3 1};后缀:{2,1  2,3  1  2,2  3  1  2}

.............

应该很显而易见。

然后假定pattern[i]中最大相等缀值为pattern[0]-pattern[i]中最长的,前后缀相等的长度。

然后next值的公式大概就是:

KMP算法的理解_第8张图片

就以1 2 3 1 2 3 4为例子。

next[0]:     其中pattern[0]=1=pattern[0];所以next[0]=-1。

next[1]:     pattern[1]=2,  next[1]=pattern[0]的相等缀值,而pattern[0]没有相等缀值,也就是0,所以next[1]=0。

next[2]:     参考next[1]

next[3]:     参考next[1]。其中pattern[3]=1=pattern[0];所以next[3]=-1。

next[4]:    先看pattern[4]的序列为1 2 3 1 2具有前后相同缀{1 2},所以next[4]=0。

next[5]:    参考next[4]

next[6]:   我们看4前面的序列为1 2 3 1 2 3。显而易见可得pattern[5]的相等前后缀都是{1,2,3},缀值为3,所以推出next[6]=4。

最后我们就可以的出来子序列1 2 3 1 2 3 4的next数组为:-1  0  0  -1  0  0  3。

下面贴代码。(JAVA)

计算next数组:

	public static int[] getNext(int[]pattern){			//返回值即为next数组
		int next[]=new int[pattern.length];				//储存位置。
		int j=0;										//遍历到的位置
		int k=-1;										//到目前位置相同缀的长度
		next[0]=-1;
		while(j

计算insertOf查找结果代码:

 

	public static int indexOf(int target[],int pattern[],int begin){
		int n=target.length,m=pattern.length;
		int i=begin,j=0;								//i储存目标串遍历位置,j储存子序列遍历位置
		int[]next=getNext(pattern);						//获取next数组
		while(j

 

你可能感兴趣的:(JAVA,数据结构)