[ACW]831.KMP字符串

题目描述:求出模板串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:左神,以及网上的博客,致谢!

 

posted @ 2019-10-06 12:43  SUMay  阅读(149)  评论(0编辑  收藏  举报