KMP 模板(修订,更易懂)

KMP 模板(修订,更易懂)

之前一篇博客简单介绍了KMP的原理,但当时写的模板两个字符串数组都是从下标为0开始的,逻辑有些混乱.

这次修改了x,y下标从1开始,感觉更加自然.

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
const int M = 1e4+5;
int xlen,ylen;
int pre[M];
char x[M]; 
char y[N]; 

// x 是模式串,y 是文本串,均从1开始
void read_string(){
    scanf("%d%d",&xlen,&ylen);
    scanf("%s",x+1);
    scanf("%s",y+1);
}

// pre[i]: x串的长度为i的子串的公共前后缀长度
void get_pre(){
    pre[0] = -1;
    pre[1] = 0;
    for(int i = 2; i <= xlen; ++i){
        if(x[i] == x[pre[i-1]+1]){
            pre[i] = pre[i-1] + 1;   
        }else{
            int ptr = pre[i-1] + 1;
            while(ptr >= 1 && x[ptr] != x[i]){
                ptr = pre[ptr-1] + 1;
            }

            pre[i] = ptr;
        }
    }
}

int kmp_match(int ans[]){
    int cnt = 0;
    int xptr = 1,yptr = 1;
    while(xptr <= xlen && yptr <= ylen){
        if(xptr == 0 || x[xptr] == y[yptr]){
            ++xptr;
            ++yptr;
        }else{
            xptr = pre[xptr-1] + 1;
        }

        if(xptr == xlen + 1){
            // 注意此时x和y都已经向后移位了
            ans[++cnt] = yptr - xptr + 1;
            xptr = pre[xptr-1] + 1;
        }
    }

    return cnt;
}


int main(){
    read_string();
    get_pre();
    for(int i = 0; i <= xlen; i++){
        printf("pre[%d] = %d\n",i,pre[i]);
    }
    int ans[10];
    int cnt = kmp_match(ans);
    for(int i = 1; i <= cnt; i++){
        printf("%d\n",ans[i]);
    }

    system("pause");
    return 0;
}

posted @ 2020-11-16 09:57  popozyl  阅读(105)  评论(0编辑  收藏  举报