kmp算法自己的理解和学习

1 篇文章 0 订阅
1 篇文章 0 订阅

这个算法还是很强大和牛逼的,能想到这样的算法真的很厉害。

我这里就不介绍它是干嘛的,我直接写上它的思路和实现代码

1:kmp算法基本思路

    主方法中两个String topic_str ; 和 String pattern_str ; 
    topic_str和 pattern_str 进行遍历比较
    一个while循环条件为 j<pattern_str.length|| i<topic_str.length
    里面进行判断如果
     pattern_str.charAt(j)==topic_str.charAt(i)
     那么
     i++;j++;
     否则
     j=next[j];
    

  /**
   * 对主串s和模式串t进行KMP模式匹配
   *
   * @param s 主串
   * @param t 模式串
   * @return 若匹配成功,返回t在s中的位置(第一个相同字符对应的位置),若匹配失败,返回-1
   */
  public static int kmpMatch(String s, String t) {
    char[] s_arr = s.toCharArray();
    char[] t_arr = t.toCharArray();
    int[] next = getMySelfNextPlus(t_arr);
    int i = 0, j = 0;
    while (i < s_arr.length && j < t_arr.length) {
      if (j == -1 || s_arr[i] == t_arr[j]) {
        i++;
        j++;
      } else
        j = next[j];
    }
    if (j == t_arr.length)
      return i - j;
    else
      return -1;
  }


核心构建next[j] 数组

    基本思路如下 next数组代表的是 pattern_str 中各个字节回退的index值 例如 "abcabd" 中 'd' index=5 next[5]=2 所以再进行比较中直接回退到 'c' 
    关键在于两个索引遍历字符串 pattern_str (k,j)
    初始化时候:
    k位于-1位置,j位于1位置,next[0]=-1, next[1]=0; 理解如下:next[0]只有一个元素,说明没有可以回退位置所以到达-1(-1代表的是没有比较的所以主串i需要+1,j为0),
    next[1]前面只有一个字符,无法比较所以只能为0; 例如"abcabd"中比较第一个'b' 时候 不相等进行回退,我们只能回退到'a' next[1]=0
    
    比较的逻辑:
    记住,k代表的是 pattern_str中的前缀当前位置 ,j 代表后缀当前位置 我们计算的next[j] 都是j位置之前的前后缀位置值。例如"abcabd" 'd'位置的next[j] 算法取得前后缀为"abcab" j,k均在两个'b'上。
    if(pattern_str[k]==pattern_str[j])时候:j自增1 ,k自增1.此时next[j] = k;(这里想法是当我们jk位置值相等,我们下一个位置如果要回退说明不等,那么我就可以直接去k的位置拿值所以是next[j]=k)
    else时候:k=next[k];(这里是整个算法最难理解的地方,我们转换思路,kmp是用来匹配字符串的,那么我们是不是可以把k和j当成kmp算法基本思路中的i和j呢?
    那么是不是可以那它的前缀也就是k的位置当作 pattern_str 而j那里当作 topic_str。这样一看是否就是只需要走代码中j=next[j]这一步即可把k回退到next[k]然后重新匹配)
    
    

 public static int[] getMySelfNext(char[] p) {
    //next的含义就是代表上一个匹配的前后缀的位置。
    int[] next = new int[p.length];
    int k = -1, j = 1;
    //初始化k代表没有匹配,j代表指向第二个字符。
    next[0] = -1;
    next[1] = 0;
    while (j < p.length - 1) { //因为我们判断的是下一个next[j+1]的值所以j<p.length-1
      if (k == -1 || p[j] == p[k]) {
        j++;
        k++;
        next[j] = k;
      } else {
        //这里的思想其实就是,k=next[k] 这里我们可以理解为字串p0--pk 以及 主串pj-k---pj这一块进行kmp算法来匹配。
        //kmp回退思想所以k回退然后继续。
        k = next[k];
      }
    }
    return next;
  }


    
2.kmp算法plus

    上面的算法存在一些缺陷主要在于next数组存在问题例如当 pattern_str[j]=k这一步我们默认的是当j,k自增后也就是下一个位置如果不相等才会回退,才会到next[j]那时候直接就去k位置的值,但是问题是假设相等呢?
    如果相等的话,而且又需要回退说明k位置已经不对了所以我们应该去next[k]位置也就是  next[j]=next[k] 因为k不对那么我就去next[k]所以进行if判断后当if=true时候且k,j都自增1到达指定位置时候:
    我们再加个判断if(p[k]==p[j])为真的时候:next[j]=next[k]
    否则next[j]=k;

 


  public static int[] getMySelfNextPlus(char[] p) {
    //next的含义就是代表上一个匹配的前后缀的位置。
    int[] next = new int[p.length];
    int k = -1, j = 1;
    //初始化k代表没有匹配,j代表指向第二个字符。
    next[0] = -1;
    next[1] = 0;
    while (j < p.length - 1) { //因为我们判断的是下一个next[j+1]的值所以j<p.length-1
      if (k == -1 || p[j] == p[k]) {//我们首先判断j和k位置是否匹配
        j++;                        //匹配则判断下一个位置也就是我们next的位置的值是否相当若不相等,则next的位置值为k的下一个位置值,若相等则我要回退到k那里,但k那里相等所以我只能去next[k]那个新位置。
        k++;
        if (p[j] == p[k]) {
          next[j] = next[k];
        } else {
          next[j] = k;
        }
      } else {
        //这里的思想其实就是,k=next[k] 这里我们可以理解为字串p0--pk 以及 主串pj-k---pj这一块进行kmp算法来匹配。
        //kmp回退思想所以k回退然后继续。
        k = next[k];
      }
    }
    return next;
  }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值