hihoCoder#1015_KMP算法

题目:KMP算法

我的ac代码:

#include <iostream>
#include <string>
void GetNext(const std::string T, int *& next)
{
	int i = 0;
	int j = -1;
	int len = T.length();
	next[0] = -1;
	while (i < len)
	{
		if (j == -1 || T[i] == T[j])
			next[++i] = ++j;
		else
			j = next[j];
	}
}
int KMP(const std::string& S, const std::string& T, int *& next)
{
	int i = 0, j = 0;
	int sum = 0;
	while (i < S.size())
	{
		if (j == -1 || S[i] == T[j])
		{
			if (j == T.size() - 1)
			{
				++sum;
				j = next[j];
			}
			else
			{
				++i;
				++j;
			}
		}
		else
			j = next[j];
	}
	return sum;
}
int main()
{
	int N;
	std::string S, T;
	
	std::cin >> N;
	while (N--)
	{
		std::cin >> T >> S;
		int *next=new int [T.size()+1];
		GetNext(T, next);
		std::cout << KMP(S, T, next) << std::endl;
		T.clear();
		S.clear();
		delete []next;
		next = NULL;
	}
	return 0;
}

之前对KMP算法不是很了解,看了一些资料后感觉理解了一点,下面自己写下自己对KMP的认识吧。

看了很多资料,真的是乱,有些数组从0开始,有些从1开始,看的头疼,这里是从0开始的。

我觉得,KMP算法主要是next数组的理解,我们先假设主串为: 《hihoCoder#1015_KMP算法》,模式串为《hihoCoder#1015_KMP算法》。那么,当主串和模式串失配时,假设失配位置为《hihoCoder#1015_KMP算法》《hihoCoder#1015_KMP算法》,即《hihoCoder#1015_KMP算法》,此时模式串向右滑动的可行距离有多远,也就是说,当主串第《hihoCoder#1015_KMP算法》个字符和模式串第《hihoCoder#1015_KMP算法》个字符失配时,主串第《hihoCoder#1015_KMP算法》(《hihoCoder#1015_KMP算法》不会回溯)个字符应该和模式串哪个字符比较?

     我们假设此时主串第《hihoCoder#1015_KMP算法》个字符应该与模式串的第《hihoCoder#1015_KMP算法》个字符继续比较,则模式串前《hihoCoder#1015_KMP算法》个字符必有下列关系式:

《hihoCoder#1015_KMP算法》         (1)

又因为失配位置是在《hihoCoder#1015_KMP算法》《hihoCoder#1015_KMP算法》《hihoCoder#1015_KMP算法》),也就是说,模式串第《hihoCoder#1015_KMP算法》位置前面的字符和主串是匹配的,即:

《hihoCoder#1015_KMP算法》      (2)

(2)式中,我们如果只取“部分”,即取k个字符,,则:

                                                                                        《hihoCoder#1015_KMP算法》     (3)

那么,由式(1)和(3),可以得到:

                                                                             《hihoCoder#1015_KMP算法》     (4)

如果令《hihoCoder#1015_KMP算法》,那么,这个《hihoCoder#1015_KMP算法》的含义就是式(4)。

并且,由k的用途我们知道,《hihoCoder#1015_KMP算法》的意思就是,模式串中第《hihoCoder#1015_KMP算法》个字符不匹配,就用模式串中的第《hihoCoder#1015_KMP算法》个字符和主串比较。

那么,如何求得next数组?

首先,由于我们的字符串下标从0开始,所以:

《hihoCoder#1015_KMP算法》

然后,我们设《hihoCoder#1015_KMP算法》,由《hihoCoder#1015_KMP算法》的含义(4)知,模式串存在如下关系:

《hihoCoder#1015_KMP算法》   (就是式(4)),

那么,此时《hihoCoder#1015_KMP算法》如何计算?我们分情况讨论:

(1)《hihoCoder#1015_KMP算法》

则表明模式串中存在如下关系:

《hihoCoder#1015_KMP算法》           (5)

根据《hihoCoder#1015_KMP算法》和式(4)的关系可知,由式(5)可以得到:

《hihoCoder#1015_KMP算法》

(2)《hihoCoder#1015_KMP算法》

《hihoCoder#1015_KMP算法》

我们将模式串看成一个主串,”另一个模式串“作为模式串,那么在模式串的第k位出现不匹配,所以,根据next数组的作用,应该用模式串的第《hihoCoder#1015_KMP算法》个字符和主串中的《hihoCoder#1015_KMP算法》比较,我们令《hihoCoder#1015_KMP算法》,如果《hihoCoder#1015_KMP算法》,那么有:

《hihoCoder#1015_KMP算法》

所以就有:

《hihoCoder#1015_KMP算法》,也就是:

《hihoCoder#1015_KMP算法》

同样,如果《hihoCoder#1015_KMP算法》,继续next,直至《hihoCoder#1015_KMP算法》在模式串中找到匹配的字符,或者,“找到头”也找不到匹配的字符。

如果“找到头”也找不到匹配的字符,则:

《hihoCoder#1015_KMP算法》

下面,举个例子:

《hihoCoder#1015_KMP算法》

           我们已经求得next[6]=3,现在要求next[7]。由next[6]=3得:

《hihoCoder#1015_KMP算法》

《hihoCoder#1015_KMP算法》

所以:

《hihoCoder#1015_KMP算法》

所以:

next[7]=4

我们继续求next[8],,因为next[7]=4有《hihoCoder#1015_KMP算法》,但是《hihoCoder#1015_KMP算法》,所以下一个和“主串”中《hihoCoder#1015_KMP算法》比较的字符是第《hihoCoder#1015_KMP算法》,即第1(注意,下标从0开始)个字符,此时:《hihoCoder#1015_KMP算法》,继续next,《hihoCoder#1015_KMP算法》,所以下一个和“主串”中《hihoCoder#1015_KMP算法》比较的字符是第0个字符,有《hihoCoder#1015_KMP算法》,所以,《hihoCoder#1015_KMP算法》

因此,我们可以得到求next数组的代码:

void Next(std::string &T,int next[])
{
	int len = T.length();
	next[0] = -1;
	int i = 0;
	int j = -1;
	while (i < len)
	{
		if (j == -1)
		{
			next[i + 1] = 0;
			i++;
			j++;
		}
		else if (T[i] == T[j])
		{
			next[i + 1] = j + 1;
			i++;
			j++;
		}
		else
			j = next[j];
	}
}

我们注意到,j=-1和T[i] == T[j]内代码实现的操作是一样的(j=-1时,j+1刚好就是0),所以可以合并在一起:

void Next(std::string &T,int next[])
{
	int len = T.length();
	next[0] = -1;
	int i = 0;
	int j = -1;
	while (i < len)
	{
		if (j == -1 || T[i] == T[j])
		{
			next[i + 1] = j+1;//这里不能写next[i]+1,因为j可能是经过next[j]得到的
			i++;
			j++;
		}
		else
			j = next[j];
	}
}

再简洁一点可以写成:

void Next(std::string &T,int next[])
{
	int len = T.length();
	int i = 0;
	int j = next[0] = -1; 
	while (i < len)
	{
		if (j == -1 || T[i] == T[j])
			next[++i] = ++j;
		else
			j = next[j];
	}
}

  

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/sinat_30071459/article/details/51024492
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞