题目描述:求出模板串P在模式串S中所有出现的位置的起始下标。
tips:
1.next数组多求一位,求出整个P串的最大前后缀匹配长度。
2.当匹配成功时,p串向后推多少?此时s串的指针i1已经指向完全匹配的下一位了,只需要i2跳跃到整个串最大前后缀匹配长度指示的位置开始比较就行;用反证法假设证推矛盾。
3.位置下标从0开始,长度与下标的对应。
4.next数组有递推的感觉,刚开始的处理,比如i-1和cn=0的处理,就很巧妙。
//1.首A代码,尽管写的比较丑,还是留影纪念下吧 //2.卡了好久的一个点是,自己觉得逻辑没有错误,输出就是不对,是什么原因呢?? //输出语句的位置没放在while循环里 //3.自己独立完成推了第一次匹配成功后,该怎么接着继续匹配? //我的解法是求next数组时,多求一位,求出整个P串的最长前缀和最长后缀的匹配长度 //匹配成功时,i1已经指向完全匹配位置的下一位, //4.用反证法进行证明:i2指针的跳跃和被否定掉的位置不可能匹配成功,即不可能出现更长的前缀和后缀相匹配 //5.一路都相等;没配上之前,两个字符串都一样 //6.注意比较完之后下标指针i1、i2的更新 #include<iostream> #include<cstdio> #include<string.h> using namespace std; const int N=10010; const int M=100010; char p[N],s[M]; int ne[N]; int n,m; void getne(char* p){ int pLen=strlen(p); ne[0]=-1; ne[1]=0; int i=2; int cn=0; while(i<=pLen){ if(p[i-1] == p[cn]){ ne[i++]=++cn; }else if(cn > 0){ cn=ne[cn]; }else{ ne[i++]=0; } } /* for(int i=0;i<=pLen;i++){ printf("%d ",ne[i]); } */ return ; } int main(){ cin>>n>>p>>m>>s; getne(p); int pLen=strlen(p); int sLen=strlen(s); int i1=0;//甲指针 int i2=0;//乙指针 for(;i1<m;i1++){ while(i1<sLen && i2<pLen){ if(s[i1] == p[i2]){ i1++; i2++; } else if(ne[i2]== -1)// 思考ne[i2]什么时候等于-1?当ne[i2]==-1时,i2已经指向了p串开头0 { i1++; } else{ i2=ne[i2]; } if(i2 == pLen){ printf("%d ",i1-pLen); i2=ne[i2]; } } } return 0; }View Code
ps:kmp算是才刚刚解锁,学习花了大概一周的时间
ref:左神,以及网上的博客,致谢!