KMP算法——关于next数组的求值

关于kpm获取next数组方法的一点理解
先贴上得到next[]最原始的代码,再详细分析

 1 public static int[] getNext(String ps) {
 2 
 3     char[] p = ps.toCharArray();
 4 
 5     int[] next = new int[p.length];
 6 
 7     next[0] = -1;
 8 
 9     int j = 0;
10 
11     int k = -1;
12 
13     while (j < p.length - 1) {
14 
15        if (k == -1 || p[j] == p[k]) {  
16 
17            next[++j] = ++k;
18 
19        } else {
20 
21            k = next[k];
22 
23        }
24 
25     }
26 
27     return next;
28 
29 }

我们最先需要理解一下几点
P表示模式串,T表示主串
1.next[]数组是用来做什么的?
——用来保存当字符串匹配在第j位发生失配时,我们没必要将主串回溯,我们只需要将模式串数组检索下标移动k个位置就可以满足需求,而next[]数组就是用来保存当模式串在任意一个位置发生失配时需要移动的k的值
“因为在P的每一个位置都可能发生不匹配,也就是说我们要计算每一个位置j对应的k,所以用一个数组next来保存,next[j] = k,表示当T[i] != P[j]时,j指针的下一个位置。另一个非常有用且恒等的定义,因为下标从0开始的,k值实际是j位前的子串的最大重复子串的长度。”

2.为什么要将-1赋值给next[0]?
——当j为0时,如果这时候不匹配,怎么办?

图一

像上图这种情况,j已经在最左边了,不可能再移动了,这时候要应该是i指针后移。所以在代码中才会有next[0] = -1;这个初始化。
如果是当j为1的时候呢?
图二

显然,j指针一定是后移到0位置的。因为它前面也就只有这一个位置了~~~

3.数组第15-25行:
我们可以修改为(便于快速理解)

if(k==-1||p[j]==p[k]){
      j=j+1;
      k=k+1;
      next[j]=k;
}else{
    k=next[k];
}

这里我们比较的是第k个位置和第j个位置的值,但是我们却是为了给
next[j+1]赋值,是因为当在j位置发生失配时,我们都是在模式串的子字符串[0,j-1]内寻找前缀和后缀(这里不太懂也没有关系,看完图一和图二会有更详细的解释)

二.下面就是运行到每一步时,next【】值的变化

一.png
二.png

三.next[]数组求解优化

来看一个例子:
例一.png

显然,当我们上边的算法得到的next数组应该是[ -1,0,0,1 ]
所以下一步我们应该是把j移动到第1个元素:


移动.png

不难发现,这一步是完全没有意义的。因为后面的B已经不匹配了,那前面的B也一定是不匹配的,同样的情况其实还发生在第2个元素A上。
显然,发生问题的原因在于P[j] == P[next[j]]。

我们只需要在原算法第16行加上一个判断语句

 1 public static int[] getNext(String ps) {
 2 
 3     char[] p = ps.toCharArray();
 4 
 5     int[] next = new int[p.length];
 6 
 7     next[0] = -1;
 8 
 9     int j = 0;
10 
11     int k = -1;
12 
13     while (j < p.length - 1) {
14 
15        if (k == -1 || p[j] == p[k]) {  
16               if(p[++j]==p[++k]{   next[j]=next[k];}
17                      esle{  next[++j] = ++k;} 
18 
19        } else {
20 
21            k = next[k];
22 
23        }
24 
25     }
26 
27     return next;
28 
29 }

你可能感兴趣的:(KMP算法——关于next数组的求值)