有两个字符串:
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;
}
1831

被折叠的 条评论
为什么被折叠?



