KMP

大神传送门:https://blog.csdn.net/v_july_v/article/details/7041827#t6

【解决问题类型】有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?

步骤一:创建next数组

①寻找前缀后缀最长公共元素长度

子串对于自身各个前缀后缀的公共元素最大长度表

【结论】失配时,模式串向右移动的位数为:已匹配字符数 - 失配字符的上一位字符所对应的最大长度值

上图意思:因为子串(模式串)中的字符A跟主串(文本串)中的字符B、B、C、空格一开始就不匹配,所以不必考虑结论,直接将模式串不断的右移一位即可,直到模式串中的字符A跟文本串的第5个字符A匹配成功

 因为子串(模式串)中的字符A跟主串(文本串)中的字符B、B、C、空格一开始就不匹配,所以不必考虑,直接将模式串不断的右移一位即可,直到模式串(子串)中的字符A跟文本串(主串)的第5个字符A匹配成功

继续往后匹配,当模式串(子串)最后一个字符D跟文本串(主串)匹配时失配,显而易见,模式串需要向右移动。但向右移动多少位呢?因为此时已经匹配的字符数为6个(ABCDAB),然后根据《最大长度表》可得失配字符D的上一位字符B对应的长度值为2,所以根据之前的结论,可知需要向右移动6 - 2 = 4 位。

②求next数组

上文利用这个《最大长度表》和结论进行匹配时,我们发现,当匹配到一个字符失配时,其实没必要考虑当前失配的字符,更何况我们每次失配时,都是看的失配字符的上一位字符对应的最大长度值。如此,便引出了next 数组。

不难发现:next 数组相当于“最大长度值” 整体向右移动一位,然后初始值赋为-1

【结论】失配时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值

                       

根据模式串“ABCDABD”的next 数组可知失配位置的字符D对应的next 值为2,代表字符D前有长度为2的相同前缀和后缀(这个相同的前缀后缀即为“AB”),失配后,模式串需要向右移动j - next [j] = 6 - 2 =4位。

void GetNext(char* p,int next[])
{
	int pLen = strlen(p);
	next[0] = -1;
	int k = -1;
	int j = 0;
	while (j < pLen - 1)
	{
		if (k == -1 || p[j] == p[k])    //p[k]表示前缀,p[j]表示后缀
		{
			++k;
			++j;
			next[j] = k;
		}
		else 
		{
			k = next[k];
		}
	}
}

next还可以优化
但优化之后next里面存的就不是p[j]之前中前后缀的最大相同字符个数
void getnext(char p[], int next[])
{
	next[0] = -1;
	int j = 0, i = -1;
	while (j

步骤二:

如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;

如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。

换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值,即移动的实际位数为:j - next[j]

 

 

你可能感兴趣的:(数据结构学习记录)