KMP

kmp

以前觉得好难,现在感觉好简单。再次梳理一下。
首先构造next数组用来代表前缀重复最大的长度。如果prelen和i的字符相等那么直接next[i]=prelen+1,同时i和prelen递增;如果不相等,prelen是0直接加入0;如果不是0,那么取next[prelen-1]也就是避免重复比较。然后是正式比较,如果s[i]==p[j]那么说明相等,i和j自增即可;如果不相等,但是j是0说明一开始就不同,直接i++;如果j不是0说明有比较的那么j=next[j-1]避免重复比较。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
    int n,m;
    string p,s;
    cin >> n >> p >> m >> s;
    vector<int> next(n,0);
    
    //构造next
    next[0] = 0;//初始化第一个为0
    int prelen = 0;
    int i = 1;
    while(i<n){
        if(p[i]==p[prelen])next[i++]=++prelen;//比较相等那么next为prelen+1,i自增
        else if(prelen==0)next[i++]=0; //如果是0直接纳入,i自增
        else prelen = next[prelen-1];  //不是0,取其前缀继续
    }
    //比较
    int j = 0;
    i = 0;
    vector<int>res;
    while(i<m){
        if(s[i]==p[j]){i++;j++;}//相等二者共同增加
        else if(j>0) j=next[j-1];//不相等,j大于0那么取前缀
        else i++;//直接不等,直接增加
        if(j==n){res.push_back(i-j);j=next[j-1];}//如果达到长度则记录并且更新j
    }
    
    for(int x:res)cout << x << " ";
    return 0;
}
posted @ 2025-07-31 17:49  .N1nEmAn  阅读(7)  评论(0)    收藏  举报