KMP算法——本人见解

 

什么是KMP算法:

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

 

现在我们呢来举一个例子把!

 

问题描述:

"aaccbcaabaabcaccac"这个字符串中找"abaabcac",我们如果全凭视力来查找的话,估计很快就会找到答案,但是如果字符串特别长呢?你还用视力嘛?怕是行不通了。

 

其实这个模式串匹配算法很多,为什么要着重的将KMP算法呢?因为KMP算法效率高!

那么为什么KMP算法效率会高呢?当然效率高是相对的,像简单的BF算法也可以解决模式串匹配问题,但是其效率十分低下,没有将匹配失败带给我们的有用信息利用起来,而我们的KMP算法就是充分挖掘了失败的匹配带给我们的有用信息利用起来,实现了主串无回溯,提高匹配效率!

 

我相信大家都已经明白KMP算法是干什么的了,我在这里就直接给大家说干货了!

 

1.next数组

在我看来,KMP算法难就难在这个next数组上,我以前刚接触的KMP算法的时候,看了很多博客,但是我发现它们都有一个通病,他们会告诉你怎么求next数组,但不会告诉你为什么这么求,这就让我很不爽!

我们就求解一下上面的"abaabcac"所对应的next数组把!

 

如何求next数组呢?

我给出的解释就是:当前位置所对应的字符的 最大     真前缀=真后缀 再加上1,就是当前字符所对应的下标的next值!

 其中的"T1...TK-1"就是当前字符所对应的最大真前缀,"Tj-k+1...Tj-1"就是其对应的最大真后缀串。

 注意:一般数组的零号位置做监视哨,所以j=1就是当前数组的第一个存储元素所在位置。

 

第一个字符a:按照定义next[1]=0;

第二个字符b:按照定义,根本不存在符合条件的K,next[2]=1;

第三个字符a:按照定义,其真前缀有且仅有a,真后缀有且仅有b,且a!=b,next[3]=1;

第四个字符a:按照定义,可以看出 最大且满足 真前缀==真后缀 的只有a==a,next[4]=2;

第五个字符b:按照定义,可以就看出其next[5]=2;

第六个字符c:按照定义,可以看出,ab==ab,所以next[6]=3;

第七个字符a:按照定义,next[7]=1;

第八个字符c:按照定义,可以看出 a==a,所以next[8]=2;

 

接下来我们有算法实现求next数组:

 

	//求next数组
	public static int[] getNext(String[] model) {
		//next数组
		int[] next=new int[model.length];
		
		int j=1;
		
		int k=0;
		
		next[1]=0;
		
		while(j<model.length-1) {
			
			if( k==0 || model[j]==model[k]) {
				++j;
				++k;
				next[j]=k;
			}else {
				k=next[k];
			}
		}
		
		return next;
	}

 

这里我要说一下当Tk!=Tj时为什么是k=next[k],而不是别的。为什么要这样写呢?你想一想k是什么?是你的上一个字符的        真前缀=真后缀 的最大长度,我们现在已经失配了,我们能得到的最好结果就是看当前字符何next[k]处的字符是否匹配,next[k]代表什么?代表第K个字符,我们的前一个字符匹配到了K个长度,我们既然在第K加1个字符处失配,那么我们当前效率做高的做法就是看看能否实现K长度个字符的匹配!

 

下面是KMP算法的实现!

/**
 * 模式串匹配算法KMP
 * @author king
 */
public class Main_Operations {
	
	//next数组
	private int[] next;
	//目标串(一般情况下字符串的零号元素做监视哨)
	private String[] aim={"Listener","a","b","a","a","b","c","a","c"};
	//待查串
	private String[] model= {"Listener","a","a","c","c","b","c","a","a","b","a","a","b","c","a","c","c","a","c"};
	//运行KMP算法
	public void Run_Kmp() {
		//获得next数组
		next=Next_Operations.getNext(aim);
		//待查串的当前匹配位置
		int i=1;
		//目标串当前匹配位置
		int j=1;
		while( i<model.length &&  j<aim.length ) {
			
			if(j==0 || model[i]==aim[j]) {
				i++;
				j++;
			}else {
				j=next[j];
			}
		}
		System.out.println(i-aim.length+1);
	}
	
	@Test
	public void fun1() {
		Run_Kmp();
	}
}

谢谢观赏!

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值