KMP算法(代码+图解证明)

        KMP算法用于字符串匹配,是相较于朴素字符串匹配。所谓朴素字符串匹配就是从头到尾开始一个位置一个位置匹配,当前位置匹配失败则会从下一个位置开始继续匹配。

        KMP算法则是可以跳,能往前跳多远就往前跳多远。我们知道算法尽量要简化计算、去冗余、记忆搜索。KMP就是利用了去冗余的思想往前跳到某一位置继续匹配。而中间未匹配的丝毫不会有影响,这要归结于我们next数组的定义。

       所谓next数组中next[i]就是记录如果当前位置位置不匹配,字符串可以往前跳多远进行重新匹配。所以next[i]就是计算i之前字符串的最大回文长度(就是前缀和后缀相等的最大长度)。中间跳跃的点都是不用匹配的点,这个可以证明。

KMP算法(代码+图解证明)_第1张图片

       如图,我们中间跳过的位置,如果存在有用的,即b'>b的长度。这种情况反证了我们b计算错误,也即我们next数组没求最长的,也就是没求对。故而,跳过的就是没用的。

       那么指导跳跃的next数组的求法如下图所示。

KMP算法(代码+图解证明)_第2张图片

       上图演示的是next[i]这一位的计算方法,使用到了递归。这些说明白了,直接上代码。

#include
#include
using namespace std;

int * getNextArray(string ms) {
		if (ms.length() == 1) {
			int *a=new int[1];
			a[0]=-1;
			return a;
		}
		int* next = new int[ms.length()];
		next[0] = -1;
		next[1] = 0;
		int pos = 2;
		int cn = 0;
		while (pos < ms.length()) {          //next数组从2之后大于等于0
			if (ms[pos - 1] == ms[cn]) {
				next[pos++] = ++cn;
			} else if (cn > 0) {
				cn = next[cn];
			} else {
				next[pos++] = 0;
			}
		}
		return next;
	}

//s是原串,m是模式串
 int getIndexOf(string s, string m) {
		if (s == "" || m == "" || m.length() < 1 || s.length() < m.length()) {
			return -1;
		}
		
		int si = 0;
		int mi = 0;
		int* next = getNextArray(m);
		while (si < s.length() && mi < m.length()) {
			if (s[si] == m[mi]) {
				si++;
				mi++;
			} else if (next[mi] == -1) {
				si++;   
			} else {
				mi = next[mi];
			}
		}
		return mi == m.length() ? si - mi : -1;
	}

      KMP算法其实不难,仔细研究下就可以理解了。


你可能感兴趣的:(算法)