KMP算法之next数组的求解

1. 假设模式串(子串)p: 为 "bbabba" ,扫描模式串的指针为j, 当扫描到模式串不匹配的时候模式串回退的位置为k

需要弄清楚的是next数组的含义,比如next[j] = k表示的是当p[j] == p[k]的判断不成立的时候(失配)k应该回退到模式串的下标为k的next[k]位置上

比如模式串为bbabba,下面是求解过程

                 b b a b b a

    (p[k]为该行中最后一个字符,写成下面的形式是为了更好的观察,其实还是同一个字符串)  

    p[0] = b                               b    netx[0] = -1   j = 0 k = -1

    p[1] = b                           b  b    next[1] = 0    j = 1 k = 0

    p[2] = a                        b b  a    next[2] = 1    j = 2  k = 1

    p[3] = b                     b b a  b    next[3] = 0    j = 3 k = 0 

    p[4] = a                  b b a b  a    next[4] =1    j = 4 k = 1

    p[5] = a               b  b a b b a    next[5] = 2    j = 5 k = 2

要求解next[2],首先要看上一次的p[j]和p[k] 其中上一次的j和k为:j = 1 k = 0

判断p[1]是否等于p[0] 假如相等则next[2] = ++k = 1,  假如不相等k = next[k],在这里例子中p[1] = p[0] ,所以next[2] = ++k = 1     

求解next[3] , 其中next[2] = 1 : j = 2 k = 1 那么判断p[2]是否等于p[1] ,这里p[2]!=p[1]所以 j = 2 k = next[1] = 0 判断p[2] 是否等于p[0] 发现不等那么j = 2 k = next[0] = -1,此时  k = -1,当k = -1 的时候next[3] = ++k = 0 

求解next[4], 其中next[3] = 0 : j = 3 k = 0 那么判断p[3]是否等于p[0] 发现相等那么next[4] = ++k = 1

求解next[5], 其中next[4] = 1 : j = 4 k = 1 那么判断p[4]是否等于p[1] 发现相等那么next[5] = ++k = 2

那么模式串 "bbabba"的next数组为 : -1 0 1 0 1 2 

上面的模式是基于代码的思路来的

 

求解next数组实际上也是求解最长前缀与最长后缀的最长匹配,比如像上面的模式串 "bbabba"(求解next[k]不包含模式串下标为k这个位置的字符所求解的前缀和后缀)

第一次next[0]]:  b  next[0] = -1 

第二次next[1]:  bb next[1] = 0

第三次next[2]:  bba 求解next[2]的时候不包括bba的最后一个字符,所以bba的前缀为:  b 

后缀为b 所以最长前缀与最长后缀的最长匹配为b,有一个所以next[2] = 1

第四次next[3]:  bbab   bbab的前缀为: b和bb

后缀为a和ba,前缀和后缀都不匹配,所以next[3] = 0

第五次next[4]:  bbabb   bbabb的前缀为: b, bb,bba

后缀为b,ab,bab,所以最长前缀与最长后缀的最长匹配为b,有一个所以next[4] = 1

第六次next[5]:  bbabba   bbabba的前缀为: b, bb,bba,bbab

后缀为b,bb,abb,babb,所以最长前缀与最长后缀的最长匹配为bb,所以next[5] = 2

2. 下面是具体的代码实现:

public class Main{
	public static void main(String[] args) {
		//该方法也可以用来求解字符串中存在的匹配的字符串在源串中匹配的次数因为有计数变量count
		String s = "babababcbabababb";//长度为16
		//String p = "bababb";
		String p = "babab";
		System.out.println(indexOf1(s,p));
	}
	
	private static int indexOf1(String s,String p){//s:"babababcbabababb"
		if(s.length()==0||p.length()==0)return -1;//p:"bababb"
		if(p.length()>s.length())return -1;
		int next[] = next(p);//next:{-1,0,0,1,2,3} p:bababb
		int i = 0;//s位置
		int j = 0;//p位置
		int sLen = s.length();
		int pLen = p.length();
		int count = 0;
		while(i<sLen){
			if(j==-1||s.charAt(i)==p.charAt(j)){
				i++;
				j++;
			}else{
				j = next[j];
			}
			if(j==pLen){
				count++;
				//j回溯到上一个位置
				j=next[j-1];
				//i往前走一格
				i--;
				//return i - j;
			}
		}
		return count;
	}

	private static int[] next(String ps) {
		int pLength = ps.length();//pLength = 6
		int next[] = new int[pLength];//next:{-1,0,0,0,0,0} pLength = 6
		char p[] = ps.toCharArray();
		next[0] = -1;
		if(ps.length()==1){
			return next; //ps:bababb
		}
		next[1] = 0;
		int j = 1;
		int k = next[j];
		while(j<pLength-1){
			if(k<0||p[j]==p[k]){
				next[++j]=++k;
			}else{
				k = next[k];
			}
		}
		return next;
	}
}

其中还有其他例子:

String p = "ababaa";  //next:-1 0 0 1 2 3
String p = "bababb";  //next:-1 0 0 1 2 3
String p = "bbabba";  //next:-1 0 1 0 1 2
String p = "babbab";  //next:-1 0 0 1 1 2

想的时候可以求解next数组的时候是求解最长前缀与最长后缀的重叠部分

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值