KMP算法,可读性较好的一种实现。

最近看了July的博文《从头到尾彻底理解KMP》。讲解得非常详细,也给我一些启发,让我仔细地思考了一下KMP算法。

作为产品维护工程师,我们会更多地考虑代码的可维护性,即代码的可读性。July的文章中,在计算next数组时,给next数组的第0位设置为-1做为旗标使用,并且在字符失配的情况下,令k=next[K],这样的写法让人比较难以理解。于是我也写了一份计算next数组的实现,供大家参考。

 1     public static int[] getNextArray(String p)
 2     {
 3         int len = p.length();
 4         int next[] = new int[len];
 5         next[0] = -1;
 6         if (len >= 2)
 7         {
 8             next[1] = 0;
 9             int cursor = 2;
10             int flag = 0;
11             int value = 0;
12 
13             while (cursor <= len -1)
14             {
15                 if (p.charAt(cursor - 1) == p.charAt(flag))
16                 {
17                     ++flag;
18                     ++value;
19                 }
20                 else
21                 {
22                     if (flag != 0)
23                     {
24                         flag = 0;
25                         value = 0;
26 
27                         if (p.charAt(cursor - 1) == p.charAt(flag))
28                         {
29                             ++flag;
30                             ++value;
31                         }
32                     }
33                 }
34                 next[cursor] = value;
35                 ++cursor;
36             }
37         }
38 
39 
40         return next;
41     }

next数组的含义是:设i是next数组中的一位,则next[i]的值的含义是在这一位之前自负串中相同的前缀和后缀的长度。比如字符串ABCABD,当i=5,即字符D位置,该位置之前的字符串为ABCAB,有相同的前后缀AB,其长度为2,则对应next数组的值为2。需要指出的是,位置0和1比较特殊。位置0之前没有字符串,对应next数组的值设置为-1,这个值是做为占位符存在的,其值除了做为旗标外并无其他意义。而位置1之前,只有一个字符,此处认为其前后缀为0。

我的实现和之前博文描述的不同之处在于适配时候的处理。在计算next数组时,当适配发生的时候,如果当前字符不是和字符串的第一位进行比较,需要再和字符串第一位进行一次比较。在此实现中,我用flag代表前缀的游标,value做为当前next数组的值,可以看到,这两个变量的增减变化是同步的。其实是可以合在一起的。然而,合在一起的代价就是对程序理解的变得更困难了,因为flag和value在含义上并没有必要的联系。这也是之前next[k]=k在理解上面的难点。

next数组完成之后,KMP算法的实现也就变得唾手可得了。附上我自己的实现供大家参考。

 1     public static int kmpMatch(String s, String p)
 2     {
 3         int ret = -1;
 4         int i = 0;
 5         int j = 0;
 6 
 7         int[] next = getNextArray(p);
 8         while ( i < s.length() - p.length()+1)
 9         {
10             if (s.charAt(i) == p.charAt(j))
11             {
12                 if (j == p.length() -1)
13                 {
14                     ret = i - j;
15                     break;
16                 }
17                 else
18                 {
19                     ++i;
20                     ++j;
21                 }
22             }
23             else
24             {
25                 if (j != 0)
26                 {
27                     j = next[j];
28                 }
29                 else
30                 {
31                     ++i;
32                 }
33             }
34 
35         }
36 
37         return ret;
38     }
原文地址:https://www.cnblogs.com/cutepangpanghu/p/4964525.html