• 字符串匹配


    匹配算法

    主要是清楚KMP算法,next数组生成算法

    暴力算法BF算法

    /**
       * 暴力解法
       * @param s
       * @param p
       * @return
       */
      private static int indexOf(String s, String p) {
        int index = 0;
        int i = index;
        int j = 0;
        while (index < s.length()) {
          if (s.charAt(i) == p.charAt(j)) {
            i++;
            j++;
            if (j == p.length())
              return index;
          } else {
            index++;
            i = index;//扫描指针以i为起点
            j = 0;//j恢复为0
          }
        }
        return -1;
      }
    

    算法时间复杂度O(n*m)

    KMP算法

    简介

    KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。

    提取加速匹配的信息

    void Getnext(int next[],String t)
    {
       int j=0,k=-1;
       next[0]=-1;
       while(j<t.length-1)
       {
          if(k == -1 || t[j] == t[k])
          {
             j++;k++;
             next[j] = k;
          }
          else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!
       }
    }
    
    • 1.特殊情况
      当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。
    • 2.当 t[j] == t[k] 的情况
      举个栗子
      观察上图可知,当 t[j] == t[k] 时,必然有"t[0]…t[k-1]" == " t[j-k]…t[j-1]",此时的 k 即是相同子串的长度。因为有"t[0]…t[k-1]" == " t[j-k]…t[j-1]",且 t[j] == t[k],则有"t[0]…t[k]" == " t[j-k]…t[j]",这样也就得出了next[j+1]=k+1。
    • 3.当t[j] != t[k] 的情况
      关于这种情况,在代码中的描述就是“简单”的一句 k = next[k];。我当时看了之后,感觉有点蒙,于是就去翻《数据结构教程》。但是这本书里,对于这行代码的解释只有三个字:k 回退…!于是我从“有点蒙”的状态升级到了“很蒙蔽”的状态,我心想,k 回退?我当然知道这是 k 退回,但是它为什么要会退到 next[k] 的位置?为什么不是回退到k-1???巴拉巴拉巴拉…此处省略一万字。

    至此,算是把求解数组 next 的算法弄清楚了(其实是,终于把 k = next[k] 弄懂了…)

    因为这个算法神奇难解之处就在k=next[k]这一处的理解上,网上解析的非常之多,有的就是例证,举例子按代码走流程,走出结果了,跟肉眼看的一致,就认为解释了为什么k=next[k];很少有看到解释的非常清楚的,或者有,但我没有仔细和耐心看下去。我一般扫一眼,就大概知道这个解析是否能说的通。仔细想了三天,搞的千转百折,山重水复,一头雾气缭绕的。搞懂以后又觉得确实简单,但是绕人,烧脑。
    都明了之后就可以手写 KMP 的代码了

    int KMP(String s,String t)
    {
       int next[MaxSize],i=0;j=0;
       Getnext(t,next);
       while(i<s.length&&j<t.length)
       {
          if(j==-1 || s[i]==t[j])
          {
             i++;
             j++;
          }
          else j=next[j];               //j回退。。。
       }
       if(j>=t.length)
           return (i-t.length);         //匹配成功,返回子串的位置
       else
          return (-1);                  //没找到
    }
    
  • 相关阅读:
    一位资深程序员大牛给予Java初学者的学习路线建议
    Java基础部分全套教程.
    Java进阶面试问题列表
    成为伟大程序员的 10 个要点
    一位资深程序员大牛给予Java初学者的学习路线建议
    2年Java开发工作经验面试总结
    有效处理Java异常三原则
    Java打飞机小游戏(附完整源码)
    原生ajax封装,包含post、method方式
    手机端布局,rem布局动态获取根字体大小
  • 原文地址:https://www.cnblogs.com/Qvolcano-blog/p/14622836.html
Copyright © 2020-2023  润新知