KMP

具体学习:

请参照,讲解的非常详细:https://blog.csdn.net/v_july_v/article/details/7041827

KMP解决的问题:字符串中查找。如:S(文本串)=‘aaab’,P(模式串)=‘aab’,在S中查找是否包含P

暴力的解法:遍历S的时候,匹配P,时间复杂度O(n*m),S 长度n,P 长度m。

而KMP方法时间复杂度,O(n+m),与暴力解是质的变化。

首先了解这个概念: 

字符前面的前缀与后缀的最长匹配长度(记为MML:max match length):(1)前缀和后缀的长度要相等。(2)前缀和后缀的字符串要相等。(3)前缀和后缀的长度要最长。(4)前缀不能包含最后一个字符,后缀不能包含第一个字符。(5)不包含这个字符本身,是在当前字符的前面字符串中找。

举例:abcabcd。例如dMML是3。因为‘abc’== ‘abc’。

next[]数组:即,P中每个字符的MML,人为规定next[0] = -1,next[1] = 0。

KMP算法的流程,因为有了next数组。举例如下:

S = aabcdeaaf

P = aabcdeaak, next [] = {-1, 0, 1, 0, 0 ,0 ,0, 1,  2};

KMP的算法流程(引用了大佬的,自己写的讲不清楚):假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
    如果当前字符匹配成功(即[S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
    如果当前字符匹配失败(即S[i] != P[j]),再如果 next[j] == -1,则 i++,j不变。否则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了 j - next [j] 位。
    我们发现如果某个字符匹配成功,模式串首字符的位置保持不动,仅仅是i++、j++;如果匹配失配,i 不变(即 i 不回溯),模式串会跳过匹配过的next [j]个字符。整个算法最坏的情况是,当模式串首字符位于i - j的位置时才匹配成功,算法结束。
    所以,如果文本串的长度为n,模式串的长度为m,那么匹配过程的时间复杂度为O(n),算上计算next的O(m)时间,KMP的整体时间复杂度为O(m + n)。

代码

package basic_class_02;

public class Code_01_KMP {

	public static int getIndexOf(String s, String m) {
		if (s == null || m == null || m.length() < 1 || s.length() < m.length()) {
			return -1;
		}
		char[] ss = s.toCharArray();
		char[] ms = m.toCharArray();
		int si = 0;
		int mj = 0;
		int[] next = getNextArray(ms);
		while (si < ss.length && mj < ms.length) {
			if (ss[si] == ms[mj] ) { 
				si++;
				mj++;
			} else if(next[mj] == -1){ 
				si++;
			} else{
				mj = next[mj];
			}
		}
		return mj == ms.length ? si - mj : -1;  // ms 匹配到结尾了,说明已经匹配成功过
	}

	public static int[] getNextArray(char[] ms) {  // next数组获取
		if (ms.length == 1) {
			return new int[] { -1 };
		}
		int[] next = new int[ms.length];
		next[0] = -1;
		next[1] = 0;
		int pos = 2;
		int cn = 0;
		while (pos < next.length) {
			if (ms[pos - 1] == ms[cn]) {
				next[pos++] = ++cn;
			} else if (cn > 0) {
				cn = next[cn];
			} else {
				next[pos++] = 0;
			}
		}
		return next;
	}

	public static void main(String[] args) {
		String str = "abcabcababaccc";
		String match = "ababa";
		System.out.println(getIndexOf(str, match));

	}

}

当然肯定有比KMP更加优秀的算法,如BMSunday算法。上文链接中,讲解到了,推荐一看,流程比KMP还要简单。

posted @ 2019-01-30 18:56  Horken  阅读(126)  评论(0编辑  收藏  举报