测试样例
this is a simple text
simplep
大致思路:暴力求解进行了大量无关紧要的比较,kmp使得只有遍历一边串就可以得出结果,算法核心思想是,为串和模式分别设置两个指针i,j,都从头开始扫描,如果字符可以匹配,两指针都前进,问题主要在如果匹配失败的处理上,kmp不会让i回溯,只会让j回退(回退需要用到next数组,next数组的求法参考算法浙江大学mooc视频,结合视频更容易理解)到前缀和后缀相同的最大的前缀下标处,然后看j+1处的字符可否与i处的字符匹配,如果可以则二指针同时++,如果不可以继续回退j指针,直到j指针指向了-1(表明模式又要重头开始与串匹配),这样当i遍历完或者j指向模式末尾下标则函数结束
算法优的关键所在:字符匹配失败时,i指针(指向串)不回溯,而是可以继续向前扫描
为什么可以不回溯,发现一个奇妙的现象,
串:abcdabc…
模式:abcdabd
当前i指向e,j指向d,二者不匹配
则现在将j指向下标2(next[j-1]为2),即c,发现匹配了,i,j继续前进
#include<cstdio>
#include<string>
#include<iostream>
#include<vector>
using namespace std;
string text,s;
#define maxn 100
int match[maxn];
void getmatch()
{
int n=s.size();
match[0]=-1;
int j=-1;
for(int i=1;i<n;i++){
while(j!=-1&&s[i]!=s[j+1]){
j=match[j];
}
if(s[i]==s[j+1]){
j++;
}
match[i]=j;
}
}
int KMP()
{
int j=-1;
for(int i=0;i<text.size();i++){
while(j!=-1&&text[i]!=s[j+1]){
j=match[j];
}
if(text[i]==s[j+1]){
j++;
}
if(j==s.size()-1){
return i-s.size()+1;
}
}
return -1;
}
int main()
{
getline(cin,text);
getline(cin,s);
getmatch();
//for(int i=0;i<s.size();i++){
// printf("%d ",match[i]);
//}
printf("%d\n",KMP());
}