KMP算法(最精简的理解)

算法理解以简略为主,太多理论解释容易绕晕。

主要有以下三个数组:

  1. 匹配串:字符型

  2. 模式串:字符型

  3. next[i]数组:int

一、next[i]数组说明(先了解这个比较好学)

next[i]是专门针对模式串的(功能我们后面结合实例介绍):

模式串abcdabd
next[i]数值0000120
①首先我们了解前缀和后缀

前缀:(前缀后缀包括本身,但是在kmp算法不考虑本身)

abc的前缀包括{a,ab};

abcd的前缀包括{a,ab,abc};

可以看出前缀都是以第一个开始,依次增加,直到最后面的前一个(不包括最后一个)的集合。

后缀

abc的后缀包括{c,bc};

abcd的后缀包括{d,cd,bcd};

可以看出后缀是都是以最后一个结尾,依次在前面增加,直到第二个(不包括第一个)的集合;

②然后我们学习next[i]数组的内容

next[i]是分析模式串结构的,以便kmp算法中的使用;

下标i:对应模式串中字符的位置,而实际的含义是指包含这个字符及之前的集合;(例如上面模式串i为3则是”abcd“)

next[i]: 关于数组的内容就是下标i所对应的字符串中,前缀与后缀相同的字符串最长长度;

例如i为5时,则在“abcda”中,前缀{a,ab,abc,abcd},后缀{a,da,cda,bcda},可知相同的就是“a”,则next[5]=1;

二、kmp算法实现

在了解next[i]数组后,我们结合实例学习next[i]的功能,及kmp算法优势实现:

匹配串(第一次匹配)ababx(不匹配)xxx
模式串ababcd
匹配串(第二次匹配)ababx(开始)xxx
模式串ababcd

kmp算法的优势体现就在第二次匹配。

(一)匹配的位置如何选择:

①当前状态:第一次匹配中模式串”abab“与匹配串已匹配,但是c不匹配;

②查next[i]数组:

  1. 查看next数组中c的前一个i(内容就是“abab”);

  2. 值为2(“abab”的前缀和后缀相同的是ab,所以值为2);

③匹配:

  1. 匹配串从上一次未匹配的x开始;
  2. 模式串则从模式串str[2]开始;(下标就是2就是从②中数组获取的)

④重复前三个步骤直到匹配成功或匹配串结束(若模式串还是没有匹配完则匹配失败)。

(二)为什么可以这么做(比较通俗说明):

相信这也是大家唯一存在的疑惑了;

匹配串abcabxx
模式串abcabc

①匹配串和模式串目前匹配的部分就是”abcab“

②观察”abcab“,发现前缀的”ab"向后平移最先匹配到后缀的“ab”;

③由于”abcab“是匹配串和模式串都有的部分,那我们只需要将模式串的前缀“ab"平移到匹配串的后缀"ab"处;

匹配串abcabxx
模式串abcab

④所以利用这一特征,我们不需要再匹配“ab”,而是从模式串的c开始,这也就是为什么next[i]数组中的数字就是模式串匹配开始的位置。

⑤注意我们next[i]数组中存的是前后缀的最长公共长度,所以是最大程度减少匹配。

⑥匹配串其实一直是匹配一位往后移一位,而这一位不匹配时,就根据next数组选择模式串的一位与它继续比较。

三、代码实现

原理大家都清楚了,代码部分可以自己根据例子理解学习。
next代码不懂戳这->next数组实现说明

	public int[] getNext( String moshi ) {
		int []next = new int[moshi.length()];	
		next[0] = 0;

		for( int i = 1, j = 0; i < moshi.length(); i++ ) {		
			while( j > 0 && moshi.charAt(i) != moshi.charAt(j) ) {
				j = next[j-1];
			}			
			if( moshi.charAt(i) == moshi.charAt(j))		j++;
			next[i] = j;
		}

		return next;
	}
	
	public int kmp( String pipei, String moshi ) {
		
		int []next;
		next = getNext(moshi);
		
		int j = 0;
		for( int i = 0; i < pipei.length(); i++ ) {
			if( pipei.charAt(i) == moshi.charAt(j)) {
				j++;
			}else {
				if( i != 0 ) i--;
				if( j != 0 ) j = next[j-1];
			}			
			if( j == moshi.length() ) return (i-moshi.length()+1);		
		}
		return -1;	
	}

kmp算法是十分经典的算法,笔试中也常遇见,应掌握牢固,确保自己能随时用代码实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值