TMD ,KMP!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/shengqianfeng/article/details/101869467

以为搞清楚了BM算法的思想,就容易理解KMP了,shit!还是很难理解关于KMP算法中next数组是如何高效获得的,既然如此暂时不追究了,不过已然不妨碍把代码搞清楚!
跟BM算法类似,KMP算法中主串和模式串的比对也有类似的东西如:坏字符和好前缀。
没错,就是好前缀,BM算法中是好后缀,KMP算法中是好前缀!
在这里插入图片描述
当遇到坏字符的时候,模式串依然是需要往后移动,对于KMP算法来说依然是设法一次滑动多个位置,而不是一个字符一个字符去地低效地比较。
其实就是在好前缀本身的后缀子串中,查找最长的能跟好前缀的前缀子串匹配的串。
在这里插入图片描述
把好前缀的所有后缀子串中,最长的可匹配前缀子串的那个后缀子串叫做最长可匹配后缀子串;对应的前缀子串叫做最长可匹配前缀子串
在这里插入图片描述
如何求解好前缀的最长可匹配前缀子串和后缀子串?这个问题其实只跟模式串本身有关系,既然是好前缀,那么模式串中也一定包含好前缀,那么问题就转化为:求模式串好前缀的最长可匹配前缀子串。
在KMP算法中可以事先根据模式串本身来构建一个存储最长可匹配前缀子串的数组,这个数组的下标为模式串前缀结尾字符的下标(也就是好前缀的候选字符串),值为这个前缀的最长可匹配前缀子串的结尾字符下标。如:
在这里插入图片描述
这个next数组我们称之为“失效函数”,失效函数如何计算出来,一个简单的方法是:如图想求出前缀b[0,4]即ababa这个前缀的最长可匹配前缀的结尾字符下标,可以把b[0,4]的后缀子串全部列举出来跟b[0,4]的前缀去匹配,这样就可以得到最长的可匹配前缀的结尾字符,如图就是ababa的最长前缀子串是aba,结尾字符下标就是2,于是next[4]=2.
在这里插入图片描述
但是这种方式求next数组的值看起来比较低效,高效的方法有,极客时间争哥的课程第34节里有,可惜我没看懂!感觉变量太多了,我是看得绕进去了,感兴趣可以自己去看下,争哥的教程很棒!
下边我就假设next数组已经是被填充的,直接把代码拿上来看看:

package com.study.algorithm;

/**
 * KMP算法
 * @author jeffSheng
 * @date 20191001
 *
 */
public class Kmp {
	public static void main(String[] args) {
		String a = "ababaeabac"+"ababacd"+"xxxx";
		String b = "ababacd";
		int x = kmp(a.toCharArray(),a.length(),b.toCharArray(),b.length());
		System.out.println(x);
	}

	// a, b 分别是主串和模式串;n, m 分别是主串和模式串的长度。
	public static int kmp(char[] a, int n, char[] b, int m) {
	  int[] next = getNexts(b, m);
	  int j = 0;
	  for (int i = 0; i < n; ++i) {
	    while (j > 0 && a[i] != b[j]) { // 一直找到 a[i] 和 b[j]
	      j = next[j - 1] + 1;
	    }
	    if (a[i] == b[j]) {
	      ++j;
	    }
	    if (j == m) { // 找到匹配模式串的了
	      return i - m + 1;
	    }
	  }
	  return -1;
	}
	
	
	// b 表示模式串,m 表示模式串的长度
	private static int[] getNexts(char[] b, int m) {
	  int[] next = new int[m];
	  next[0] = -1;
	  int k = -1;
	  for (int i = 1; i < m; ++i) {
	    while (k != -1 && b[k + 1] != b[i]) {
	      k = next[k];
	    }
	    if (b[k + 1] == b[i]) {
	      ++k;
	    }
	    next[i] = k;
	  }
	  return next;
	}
	


}

代码我试过了,正常得出结果,对于kmp这个方法可以做如下图解:
在这里插入图片描述
虽然没有搞清楚next数组的高效计算方式,但是理解了整体的思想,我觉得也是够了,能够在实际软件开发中用得上也就可以了,我不觉得非要把那些细节搞清楚!TMD!KMP!

猜你喜欢

转载自blog.csdn.net/shengqianfeng/article/details/101869467
kmp