KMP算法

引入

学习一个算法要先知道它是什么,KMP算法是一种改进的字符串匹配算法。那么之前我用什么做字符串匹配呢?暴力破解,一直DF。
假设主串是ababababca,模式串是abababca。

DF算法(暴力匹配)

让模式串和主串从第一个开始匹配,如果相同,就接着比较后面的,如果不同模式串下标回到0,主串下标回到第一个匹配的位置的下一个接着比较。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
算法复杂度最后为 O(m*n)

KMP算法

KMP算法的核心,是一个被称为部分匹配表(Partial Match Table)的数组。对于模式串abababca的PMT数组如图。
在这里插入图片描述
其中index就是在模式串的下标,char就是下标对应的字符,value就是 字符串的前缀集合与后缀集合的交集中最长元素的长度
那字符串的前缀和后缀是什么?
如果字符串A和B,存在A=BS,其中S是任意的非空字符串,那就称B为A的前缀。例如,"Harry"的前缀包括{“H”, “Ha”, “Har”, “Harr”},我们把所有前缀组成的集合,称为字符串的前缀集合。同样可以定义后缀A=SB, 其中S是任意的非空字符串,那就称B为A的后缀,例如,"Potter"的后缀包括{“otter”, “tter”, “ter”, “er”, “r”},然后把所有后缀组成的集合,称为字符串的后缀集合。
那PMT的值有什么作用呢?
在这里插入图片描述
前缀和后缀是abab和abab,所以PMT是4。
在这里插入图片描述
而主串和模式串前面都是匹配过的,是相同的。在模式串中,C的前面四个字符和下标为4的字符前面四个元素是一样的。因为下标为4的元素的前四个就是和它相等的C前一个元素的后缀。所以最终模式串下标为4的元素的前面四个元素和主串此时下标前面的四个元素是相同的。
在这里插入图片描述
所以模式串不需要在退回到下标为0,只需要下标移到对应的PMT的值就可以了,主串下标不需要移动。
刚才我们真正比较时,用到的是前面一个字符对应的PMT的值,所以我们需要把PMT的值向后移一位得到真正使用的next数组,首位设为-1是为了区分首位。
在这里插入图片描述

KMP核心代码
int KMP(char * t, char * p) 
{
	int i = 0; 
	int j = 0;

	while (i < strlen(t) && j < strlen(p))
	{
		if (j == -1 || t[i] == p[j]) 
		{
			i++;
           		j++;
		}
	 	else 
           		j = next[j];
    	}

    if (j == strlen(p))
       return i - j;
    else 
       return -1;
}

那在代码中如何快速求出next数组的值呢?
我们可以采取模式串自己和自己匹配的方法。具体来说,就是从模式字符串的第一位(注意,不包括第0位)开始对自身进行匹配运算。 在任一位置,能匹配的最长长度就是当前位置的next值。如下图所示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

求next数组代码
void getNext(char * p, int * next)
{
	next[0] = -1;
	int i = 0, j = -1;

	while (i < strlen(p))
	{
		if (j == -1 || p[i] == p[j])
		{
			++i;
			++j;
			next[i] = j;
		}	
		else
			j = next[j];
	}
}

KMP最后的算法复杂度为 O(m+n)

总结

KMP相比暴力DF算法复杂度更加低,但是理解比较难。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值