KMP_字符串匹配02

KMP

源串S,模式串P,返回源串中包含的模式串的第一个字符下标

KMP是借用next[]数组将字符串匹配问题的复杂度由暴力求解法的O(m*n)降为**O(m+n)**的算法
暴力解法是用两个指针将模式串与源串字从第一个字符开始匹配,如果相同匹配下一个字符,当匹配到一个不相同的字符时,源串指针回溯到第二个字符再次与模式串第一个字符进行匹配
KMP算法只回溯模式串不对源串进行回溯,当匹配到不相同的字符时,只需要从next[]数组中得到最长匹配数组即模式串应该回溯的位置再进行匹配
next[]数组的求法
对于模式串P,next[0] = -1;j为模式串中的第几个字符;k为该字符next中对应的值

	如果Pj==Pk,next[j+1] = k + 1;j++;k++;
	否则,k继续回溯,直到满足Pj==Pk或k<0为止;
public class 字符串匹配_KMP {//O(n+m)
	public static void main(String[] args) {
		String s = "nnabababa";
		String p = "abab";
		System.out.println(indexOf(s, p));
	}
	/**
	 * @param s源串
	 * @param p模式串
	 * @return
	 */
	private static int indexOf(String s,String p){
		if(s.length()==0||p.length()==0) return -1;//如果为空串返回-1
		if(p.length() > s.length()) return -1;//如果源串长度小于模式串,返回-1
		int [] next = next(p);
		int i = 0;//s位置
		int j = 0;//p位置
		int slen = s.length();
		int plen = p.length();
		while(i<slen){
			//如果j = -1,或者当前字符匹配成功(即S[i] = P[i]),都令i++,j++
			//j=-1,因为next[0] = -1,说明p的第一位和i这个位置无法匹配,这时i,j都增加1,i移位,j从0开始
			if(j==-1||s.charAt(i) == p.charAt(j)){
				i++;
				j++;
			}else{
			//如果j != -1,且当前字符匹配失败(即S[i] !=p[j]),则令i不变,就= next[j]
			//next[j]即为j所对应的next的值
				j = next[j];
			}
			if(j == plen){//匹配成功
				return (i-j);
			}
			
		}
		return -1;
	}
	/**
	 * 构造next数组
	 * @param ps
	 * @return
	 */
	private static int [] next(String ps){
		int pLength = ps.length();
		int [] next = new int [pLength];
		char[]p = ps.toCharArray();
		next[0] = -1;
		if(ps.length() == 1){
			return next;
		}
		next[1] = 0;
		int j = 1;
		int k = next[j];//看位置j的最长匹配在哪里
		while(j<pLength - 1){
			//现在要推出next[j+1],检查j和k位置上的关系即可
			if(k<0||p[j] ==p[k]){
				next[++j] = ++k;
			}else{
				k = next[k];
			}
		}
		return next;
	}
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值