注释
设有两个串s和t,在s串中找到一个与t串相等的子串。
我们通常把s称为目标串,t称为模式串。
引言
在讲kmp算法之前,先回忆一下简单的暴力匹配算法。其大概的思路为先从目标串的第一个字符开始和模式串的第一个字符相比较,若相等,则比较后续字符,否则从目标串的第二个字符开始重新比较。依此类推,如果匹配成功,输出模式串的第一个字符在目标串出现的位置。否则,匹配失败。
下面是暴力匹配算法的实现:
#include<bits/stdc++.h>
using namespace std;
int main()
{
char s[1000],t[1000];
while(~scanf("%s%s",s,t))
{
int i = 0, j = 0;
while(i < strlen(s) && j < strlen(t)) // 保证这两个串都没有扫描完
{
if(s[i] == t[j]) //比较目标串和模式串的两个字符相同
i++,j++; //比较后续的两个字符
else //当前两个字符不相同
i = i - j + 1, //目标串的i回退
j = 0; //子串从头开始匹配
}
if(j >= strlen(t)) //j越界,表示匹配成功
cout << i-strlen(t) << endl; //输出t在s中的位置
else cout << "no" << endl;
}
return 0;
}
然后我们发现这个算法的平均时间复杂度大概是o(模式串长度*目标串长度),很容易理解,但是效率不高。所以就有人提出了kmp算法。
理解
上一篇已经大概说了对于next数组的理解,然后这里就直接开始说kmp算法了。如果对于next数组还是不理解可以去看我的上一篇文章。对于kmp算法中的next数组的理解
理解了next数组之后,发现kmp算法容易很多,大概的过程是这样的:
*int i = 0, j = 0;
while(保证模式串和目标串都没有扫描完)
{
if(两个字符串现所处的字符相等 || j == -1)
两个字符串同时向后续移动;
else
目标串保持不变,
模式串回退到next[j]的值的位置;
if(j越界)
输出t在s中的位置;
else
输出“no”;*
}
有没有发现这个和暴力匹配算法很相似,kmp算法仅仅是在两个字符串现所处的字符不相同时,直接回退模式串到next【j】值所在的位置,而不是移动目标串。但他的平均时间复杂度仅为o(模式串长度+目标串长度)。