KMP算法(一)

有两个字符串:

str1:"abc123def"

str2:"123"

此时str2是str1子串,

子串内容必须是连续的,如果str2:"123f“,那么此时str2就不是str1子串

那么就引出了今天学习的KMP算法,KMP算法就是用来告诉我们str1里面是否有个子串等于str2的

如果没有就返回-1,如果有就告诉我们出现的开头位置 

让我们梳理下逻辑

其实就是找str1中有没有完整的str2,所以从第一个位置开始对应直到找到为止

那么从第一位置a开始对照,如上图,直到完全对应,如果有点明白的感觉了就试试下面的例子

也是两个字符串

str1 :"aaaaaaaaaab"

str2:"aaaab" 

那么怎么实现这种查找子串的方法呢?先来定义一个概念:i之前的字符串,前缀与后缀的最大区配长度(对位置i来说的,与i本身无关)

举个例子:

要注意:前缀不能取到最后一个字符,后缀也不能取到开头字符,因为此时前缀和后缀肯定一样

如上图i位置搞出来的指标为3

前缀为1 2 3 4 5,但不取到整体的情况下,哪一个是相等而且最大的值

再举个例子:

像这种情况,都相等,那就选取最大的,3的位置

要注意不要取到整体,所以没有4 

好了,现在应该了解前缀后缀长度概念了,就开始步入正题

a a b a a b a
0 1 2 3 4 5 6

让i遍历,从0开始,到6结束

当i等于0,前面没有字符串,所以为-1

当i等于1,前面只有一个0位置的a,但是注意,不能取整体,所以为0

对于任何字符串来说,0位置信息是-1,1位置信息一定是0,人为规定,简单粗暴

当i等于2,前面有aa,不能取整体,所以为1

 当i等于3,前面有aab,不能取整体,所以为0

 当i等于4,前面有aaba,不能取整体,所以为1

 当i等于5,前面有aabaa,不能取整体,所以为2

 当i等于6,前面有aabaab,不能取整体,所以为3

如果前面不是特别明白,可能不知道现在在干嘛,上面的步骤,是想获取前面前缀长度后缀长度所涉及到的i前面最长的相等信息

现在这个信息获取只是针对str2的,这叫next数组,那个str1大的字符串是不需要进行这个信息获取的

接下来讲匹配过程

原来的思路:

 下面看一下有next数组之后是怎么匹配的:

 举几个例子,从简单到复杂:

多次跳跃: 

 代码实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

vector<int> get_next(string b)
{
	vector<int> result;
	int i, j;
	i = 0;
	j = -1;
	result.push_back(-1);
	while (i<b.size()-1)
	{
		if (j == -1 || b[i] == b[j])
		{
			++i;
			++j;
			if (b[i] != b[j])
				result.push_back(j);
			else if (i == 1)
				result.push_back(j);
			else
				result.push_back(result([j]);
		}
		else
			j = result[j];
	}
	return result;
}
int KMP(string a, string b)
{
	vector<int> next = get_next(b);
	int i = 0;
	int j = 0;
	while (i<(int)a.size() && j<(int)b.size())
	{
		if (j == -1 || a[i] == b[j])
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];
		}
	}
	if (j == b.size())
	{
		return i - j;
	}
	else
	{
		return -1;
	}
}

int main()
{
	string str;
	cout << "enter the string:";
	cin >> str;
	string pattern;
	cout << "enter the pattern";
	cin >> pattern;
	int result = KMP(str, pattern);
	cout << result << endl;
    system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值