zoukankan      html  css  js  c++  java
  • 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     }
  • 相关阅读:
    树链剖分总结
    主席树总结
    BZOJ1053:反素数(数学)
    CH3101 阶乘分解
    2018-2019 ACM-ICPC ECfinal I. Misunderstood … Missing
    洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)
    Codeforces Round #552 (Div. 3) 题解
    线段树合并 总结
    生成器
    Python中input()和raw_input()的区别
  • 原文地址:https://www.cnblogs.com/cutepangpanghu/p/4964525.html
Copyright © 2011-2022 走看看