串:KMP算法

KMP算法第一次看起来稍微有点复杂,其实原理还是很简单的,想清楚就理解了。

举个简单的栗子:

主串s:abcabfd

模式串t:abcabe

如果使用比较原始的方法,一个个字符进行比较,当进行到主串的i=5,s[5]=f的位置,发现与j=5,t[5]=e不匹配,则只能重新从i=2开始,与j=1再进行匹配。

而实际上,由于模式串的特点:abcabe,这个串里有两个ab,而主串f前也有个ab,则我们可以直接将f与j=3,t[3]=c进行对比,因为前面的ab是一样的,不用多一次比较了。

所以KMP算法实际上就是利用了模式串的特点,如果模式串中有较大的重复,则可以省略很多的判断,因为在主串中i是至少不动的,不用像原始的算法那样回溯。

 

KMP算法分为两个部分:

1).KMP的主体

2).next数组

 

1)的作用就是对两个串进行模式匹配,但1)需要用到2)中的next数组,因此在进行匹配前先要构建出一个next数组。

next数组的作用就类似于上面栗子中,当判断到s[5]与t[5]不相等时,直接查找next[5],next[5]指向的是f应该比较的下一个字符,这里next[5]=2,因为f前的ab与e前的ab是已知相等的,所以直接从t[2]互相对比就可以。

 

next数组的构建:

考虑模式串t,模式串的i与j位置:

若t[i]=t[j],则可知(1~i)与(j-i+1~j)间完全相等,则对next[j+1],也就是当主串不与模式串的第j+1个字符相等时,应该对比的是第i个元素的下一个,也就是next[j+1]=i+1;

若t[i]!=t[j],但可知(1~i-1)与(j-i+1~j-1)间完全相等,则对j个元素,应该首先与第next[j]个元素再对比一次,如果这个时候相等,则next[j+1]=next[j]+1;

否则继续找下一个,也就是第next[next[j]]个元素。

 

在得到next数组之后,剩下的KMP主体就很简单了,只要i与j对应的元素对比,如果s[i]==s[j],则i++,j++;否则则i与next[j]个元素对比......

代码:

可以看到,代码分了两部分:

一部分为KMP主体,另一部分为next数组的创建。

另外,对于next数组的创建中有这么一部分:

他们的作用是:

比如模式串为:aab

创建next时,next[0]自然等于-1,而next[1],如果没有这部分,将被设置为0,也就是说如果主串与模式串的i=1部分不相等时,还会去找t[0]对比,而实际上t[0]与t[1]都是a,因此是没有必要的,应该直接设置为-1。

if(t[i]!=t[j])
	next[i]=j;
else
	next[i]=next[j];


class Solution
{
public:
	int KMP(string s,string t)
	{
		vector<int> next=get_next(t);
		int i=0;int j=0;
		while(i<s.size()&&j<t.size())
		{
			if(j==-1||s[i]==s[j])
			{
				i++;
				j++;
			}
			else
				j=next[j];
		}
		if(j<t.size())
			return 0;
		else
			 return i;
	}
	vector<int> get_next(string t)
	{
		vector<int> next(t.size(),-1);
		int i=0;int j=-1;
		while(i<(t.size()-1))
		{
			if(j==-1||t[i]==t[j])
			{
				i++;
				j++;
				if(t[i]!=t[j])
					next[i]=j;
				else
					next[i]=next[j];
			}
			else
				j=next[j];
		}
		return next;
	}
};

  

 

posted @ 2019-07-23 17:54  李湘沅  阅读(322)  评论(0编辑  收藏  举报