KMP字符串匹配算法

“看毛片”算法可以说是许多人学习数据结构路上的一道坎,虽说代码并不算难,但总是写了就忘,其算法思想也是难以理解。其实多写几遍就会发现,也就那么回事。

主要思想:

kmp算法主要是通过一个next数组来加速匹配的过程,这个next数组也称为失配数组。现在我们来考虑下面这种情况,母串与匹配串匹配到了如图箭头位置,但此时A和B并不匹配,怎么办呢?注意到图中蓝色部分是相等的子串,因此我们直接移动匹配串让A和C进行比较。这就实现了加速。
在这里插入图片描述
在这里插入图片描述

上面的直接移动就是利用了next数组,next数组保存的是当匹配串中这个位置失配以后,可以移动到哪个位置继续进行匹配。现在我们来思考一下如何求得next数组。

对于匹配串,首先无需考虑的是0和1位置,当0号位置失配后无法再移动了,只能由母串移动,所以置为-1,1位置失配后自然是重新开始,所以置为0。

我们从位置2开始,设置一个cur变量从0开始,然后依次向后走,并进行匹配,这部分看代码更容易理解,需要注意的是一种可以进行加速的情况。

如下图,对于匹配串的next数组,当我们求到A位置时,由蓝色部分的相等,如果此时B和C相等,那么对于A来说,它的失配移动位置就是B后面的位置。
在这里插入图片描述
但当B和C不相等时,情况就有点复杂了,假设B的失配位置为D,由蓝色部分的相等可知此时红色箭头所指的部分也相等,所以我们把B更新为D,然后继续比较D和C是否相等。

在这里插入图片描述

代码:

vector<int> GetNext(string& s)
{
	int n = s.size();
	vector<int> next(n);
	next[0] = -1, next[1] = 0;
	if (n == 1)
		return next;
	int pos = 2, cur = 0;
	while (pos < n)
	{
		if (s[cur] == s[pos - 1])
			next[pos++] = ++cur;
		else if (cur > 0) // 加速情况
			cur = next[cur];
		else
			next[pos++] = 0;
	}
	return next;
}

int KMP(string& s, string& m)
{
	int s_len = s.size();
	int m_len = m.size();
	// 匹配串大于母串,返回不存在
	if (s_len < m_len)
		return -1;
	// 匹配串为空直接返回0
	if ( m_len == 0)
		return 0;

	int s_index = 0, m_index = 0;
	vector<int> next = GetNext(m);
	while (s_index < s_len && m_index < m_len)
	{
		if (s[s_index] == m[m_index])
		{
			++s_index;
			++m_index;
		}
		else if (next[m_index] == -1)
		{
			++s_index;
		}
		else
		{
			m_index = next[m_index];
		}
	}
	return m_index == m_len ? s_index - m_index : -1;
}

最后解释一下为什么匹配失配后匹配串可以直接向右滑动一段距离,而不用检查中间的位置。因为如果从中间开始能够匹配的话,那么在求next数组时得到的值一定是这个从中间匹配的长度,而不是原来的值,具体动手画下图就知道了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值