KMP算法难点解析

当我们实现在文本中寻找是否有特定的文本出现,我们需要实现文本匹配算法。

比如在文本:aabaabaaf 中,我们要查询是否有文本:aabaaf出现。

关于暴力求解,我就不再过多赘述,直接进入正题。

kmp算法的关键——最长公共前后缀

关于前后缀不了解的同学,我会简略说明。

前后缀:

前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串

后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

如aabaa:

前缀:a,aa,aab,aaba(从前向后)

后缀:a, aa , baa , abaa(从后向前)

最长公共前后缀(next数组的关键)

我们使用上文的列子 eg:

下标			012345
文本			aabaaf
前缀表  	        010120 
//前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。

对于a,它是没有最长公共前后缀的。

对于aa,前缀是a,后缀是a,前后缀有一个相同,这值为1

对于aab,前缀是aa,后缀是ab,不相同,值为0;

对于aaba,前缀是aab,后缀是aba,只有第一个相同,值为1;

对于aabaa,前缀是aaba,后缀是 abaa,最长相等(aa)为2个,值为2。

因此我们得到了此文本的前缀表。

next数组代码实现

//前缀表的实现
//T字符串是所需要查询的文本,len是字符串大小
void getNext(const char* T, int* next,int len)
{
	int j = 0;
	next[0] = 0;
    //第一个的前缀表一定是零,故初始化next[0],并跳过第一个
    //i=1
	for (int i = 1; i < len; i++)
	{
        //前后缀不相同的时候
		while (j > 0 && T[i] != T[j])
		{
			j = next[j - 1];//当不相等时,j回退,如果回退后还不相							//等,继续回退,直到j==0。
		}
        //相同的时候
		if (T[i] == T[j])
		{
			j++;
		}
		//将j(前缀的长度)赋给next[i]
		next[i] = j;
	}
} 

当我们有了前缀表后,就可以进行匹配了。

KMP实现:

int KMP(char* S, char* T, int* next, int Slen,int Tlen)
{
    //j指向T,T是aabaaf。
	int j = 0;
    //i指向S文本,S是aabaabaaf。
	for (int i = 0; i < Slen; i++)
	{

		if (S[i] = T[j])
		{
			j++;
		}
		else {
			while (j > 0 && S[i] != T[j])
			{
				j = next[j - 1];//退回,直到S[i]==T[j]或者j==0
			}
		}
        //匹配完成
		if (j == Tlen - 1 )
		{
			return 1;
		}

	}
	return -1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值