KMP算法用于判断一个字符是否是另一个字符的子串
概念:字符串中 一个字符前面的字符串 的前缀与后缀的最长匹配长度(短的那个字符串)
注意:前缀与后缀不可以是整个子字符串
例如:a b c a b c d , d位置的最长匹配长度为3,abc 与 abc 匹配
Next数组:长度与字符串长度一致,每个位置存储对应字符的最长匹配长度
Next数组求解:
1.初始位置,由于第一个字符前面没有字符规定, Next[0] = -1; 由于第二个字符前面只有一个字符,Next[1] = 0.
2.后续位置,使用数学归纳法,根据前面已经求过的数组值来求取Next[i];
设字符串为str:
如果str[i] == str[x1] , Next[i + 1] = Next[i] + 1;
否则把str[i]与str[x2]比较,如果相等,Next[i + 1] = Next[x1] + 1;
直到走到字符串的第一个位置,求取Next数组的代码如下:
vector<int> getNextArray(string str) {
if (str.size() == 1) {
vector<int> Next(1, -1);
return Next;
}
vector<int> Next(5);
Next[0] = -1;
Next[1] = 0;
int i = 2;//Next数组中待求的位置
int cm = 0;//与str[i - 1]比较的位置
while (i < str.size()) {
if (str[i - 1] == str[cm]) {
Next[i++] = ++cm;//cm的值一直保持和Next[i - 1]一样
}
else if (cm > 0)
{
cm = Next[cm];
}
else
{
Next[i++] = 0;//str[i - 1] != str[0]
}
}
return Next;
}
2.KMP算法的比较过程
X与Y位置不匹配,根据X位置的匹配串长度,可以把圆圈位置的字符直接与Y比较,完成加速过程
int getIndexOf(string str1, string str2) {
vector<int> Next = getNextArray(str2);
int i1 = 0;
int i2 = 0;
while (i1 < str1.size() && i2 < str2.size()) {
if (str1[i1] == str2[i2]) {
i1++;
i2++;
}
else if (i2 != 0) {
i2 = Next[i2];
}
else{
i1++;//一直后退到str2[0]都不相等,只有i1向前走一个
}
}
return i2 == str2.size() ? i1 - i2 : -1;//i2 == str2.size()代表str2走完了
}
主函数如下:
int main()
{
string match = "ababa";
string str = "abcabcababaccc";
cout << getIndexOf(str, match);
return 0;
}
时间复杂度分析
设str1长度为n, str2的长度为m,
Next数组的求取:为O(m)
总的时间复杂度为:O(n)