KMP算法(2)-代码

上一篇记录了一些理论,现在研究一下代码,KMP算法比较重要的是next函数,代码如下

public static int[] matchTable(String str) {   

  char[] p=str.toCharArray();
  int pLen = p.length;
  int[] next = new int[pLen];
  int k = -1;
  int j = 0;
  next[0] = -1; // next数组中next[0]为-1
  while (j < pLen - 1) {
    if (k == -1 || p[j] == p[k]) {
      k++;
      j++;
      next[j] = k;
    } else {
      k = next[k];
    }
  }
  return next;

}

next函数是求str的每一个字节的最大模式字串,数组的下标对应字符串的索引,数组的值对应上一个索引对应的str最大模式字串的长度

next[0]=-1:因为next数组的索引对应字符串的索引,而且当前索引对应上一个索引的最大长度,所以当i=0时,不存在上一个索引,固令next[0]=-1

分析代码:令str=“issip”   j代表str的索引  k表示最大模式字串的下标

1.当j=0时,k=-1,走if分支,k=0,j=1,num[1]=0

2.当j=1时,k=0,此时p[1]=s p[0]=i,不相等,else 分支,j不变,k=-1

3.当j=1时,k=-1,走if分支,k=0,j=2,num[2]=0

4.当j=2时,k=0,此时p[2]=s p[0]=i,不相等,else 分支,j不变,k=-1

5.当j=2时,k=-1,走if分支,k=0,j=3,num[3]=0

6.当j=3时,k=0,此时p[3]=i p[0]=i,相等,if分支,k=1,j=4,num[4]=1

7.当j=4时,k=1,此时p[4]=p p[0]=i,不相等,else 分支,j不变,k=-1

8.当j=4时,k=-1,走if分支,k=0,j=5,num[3]=0
9.循环结束
分析下来,这个代码很是漂亮,基本思路就是:
1.核心目的:已知num[k],求num[k+1]
2.如果p[j] = p[k], 则next[j+1] = next[k] + 1,已知条件:最大模式字串的第一个字节一定和str[0]相等。用上面的例子说明,当j=3时,字串“issi”的最大模式字串为“i”,
那么当j=4时,判断它的最大模式字串,根据已知条件,它的最大模式字串只能以‘i’开头,也就是我们需要比较j=4,k=1是否相等,如果相等,num[k]=num[k-1]+1
如果不想等,num[k]=0,同时我们需要把k归0
 

public int strStr(String haystack, String needle) {
  if(null==haystack || null==needle){
    return -1;
  }
  if(0==needle.trim().length()){
    return 0;
  }
  if(0==haystack.trim().length()){
    return -1;
  }
  int i=0,j=0;
  int next[]=matchTable(needle);
  while(i<haystack.length() && j<needle.length()){
    if(j==-1 || haystack.charAt(i)==needle.charAt(j) ){
      i++;
      j++;
    }else{
      j=next[j];
    }
  }
  if(j==needle.length()){
    return i-j;
  }
  return -1;
}

核心思想就是:当比较2个字符串中到k时不想等,那么我们此时就需要令j=num[k],
也就是把needle向右平移 (needle数组的长度-j+1)(相同的部分)-num[k](上一个索引对应的最大模式字串长度)

 j=next[j];这一块就相当于一个小的递归

假设当j=3时,判断失败,else分支,j=next[3]=当k=2时的索引

如果此时j!=-1 并且不想等,else 分支,j=next[2]=当k=1时的索引

.。。。

依此类推

猜你喜欢

转载自www.cnblogs.com/zy1992/p/9073313.html