KMP字符串匹配算法

KMP字符串匹配算法

       有关KMP算法的博文也是比较多的,但大多都是比较理论化的讲解,数学功底比较差的阅读起来也是相当吃力,今天来写一个比较通俗易懂的版本。

       KMP算法实际上是利用了一个a=b,b=c,那么a也就等于c的思想。首先是有一个字符串子串的匹配表。这个表实际就是用来记录子串中每一段串重复的字符个数,这样说起来可能很抽象,看个例子。已知子串为:ABCDABD
在这里插入图片描述
     继续分析下这个表,首先表中最开始A字符对应的表中数为0,B也为0,但后来A对应的就是1,B对应的就是2,那这是为什么呢?我第一次看到这个的时候也是一脸懵逼。其实他这个记录的是连续重复字符的个数,如果第一个B那么你从字符串中把B之前的全部截出来也就是AB,AB中前后没有重复的字符,第二个B的时候,截出来的字符串应该是ABCDAB,这个时候截出来的字符串中有两个字符前后是相等的,AB。所以第二个B中记录的数就是2。来看看实现这个表的代码。

	public static int[] kmpNext(String dest) {
		int[] next=new int[dest.length()];
		next[0]=0;
		for (int i = 1,j=0; i < dest.length(); i++) {
			while(j>0&&dest.charAt(i)!=dest.charAt(j)) {
				j=next[j-1];
			}
			if(dest.charAt(i)==dest.charAt(j)) {
				j++;
			}
			next[i]=j;
		}
		return next;
	}

     代码逻辑主要就是定义了两个搜索下标i,j。i初始值为1,j为0。两个同时进行遍历,当i搜索的字符跟j搜索的字符相等时,那么j++,这个j实际就是记录了相等字符的长度,如果不等时那么让匹配表中的前一个字符对应的数值赋值给j。
     为什么要这么写呢?来分析。当上面的子串遍历到第二个A的时候,两个字符串相等那么j++,j=1,到了第二个字符B的时候j再次加1,j=2。到这里思维逻辑比较差的,就不太能想明白了。因为截取的当前子串肯定比前一个截取的子串长,也就是当前截取的子串里面包含前一个截取的子串,那么如果当前的i跟j对应的字符相等,那么j前面对应的全部字符跟i对应的字符肯定也相等。因为如果前面不等,j是不会向后走的。如果当前的i跟j不等,那么继续刷新j(j=next[j-1]),实际就是把j向前调,看看前面是否相等,直到j<=0。到此匹配表介绍完毕,来看看KMP搜索。直接上代码。

	public static int kmp(String str1,String str2,int[] next) {
		
		for (int i = 0,j=0; i < str1.length(); i++) {
			
			/**
			 * j=next[j-1] 表示当j遍历到与i对象的字符不相等时 那么它j-1的字符跟i-1所对应的字符肯定相等,
			 *     查阅匹配值表next中的j-1对象的值 ,将这个值赋给j,如果j与主串的i相等那么子串的j前面的字符一定也相等
			 */
			while(j>0&&str1.charAt(i)!=str2.charAt(j)) {
				j=next[j-1];
			}
			if(str1.charAt(i)==str2.charAt(j)) {
				j++;
			}
			if(j==str2.length()) {
				return i-j+1;
			}
		}
		
		return -1;
	}

     这个代码最核心的部分我已经注释了,实际上跟匹配表中的代码一样。这里就体现了a=b,b=c,a=c的思想。比如主串:BBC1ABCDAB 1ABCDABCDABDE,子串:ABCDABD。(主串中的1代码空格)
     当主串匹配到ABCDABC时C对应的子串中的D,显然不相等,那么前面的字符串肯定是匹配相等的。这时候将匹配表next数组中的前面的这个字符B对应的数值取出来,这个值代表的就是前面相同的字符的长度。将j回溯到这个值上,再次比较j跟i是否相等,如果相等,那么j子串前面的字符肯定跟i主串前面的字符相匹配。如果不等那就继续while找相等。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值