F03【模板】KMP 算法

F03【模板】KMP 算法——信息学竞赛算法_哔哩哔哩_bilibili

 

前缀函数与 KMP 算法 - OI Wiki

P3375 【模板】KMP - 洛谷

题目:给定文本串a和模式串b,求模式串的前缀函数,求模式串在文本串中出现的所有位置。
前缀函数ne[i]:模式串[1~i]的相等真前缀与真后缀的最大长度。
例 aabaabaaa:ne[1,2,3,4,5,6,7,8,9]={0,1,0,1,2,3,4,5,2}。
求模式串的前缀函数:双指针、预判、失配前跳、匹配后移、记录ne[i]。
让模式串匹配文本串:文本串的指针一直向前,模式串的指针前跳、后移。

// KMP算法 O(|a|+|b|)
#include<bits/stdc++.h>
using namespace std;

const int N=1000010;
char a[N],b[N]; //a:文本串 b:模式串
int ne[N]; //前缀函数ne[i]:模式串[1~i]的相等真前缀与真后缀的最大长度

int main(){
  cin>>a+1>>b+1;
  int la=strlen(a+1),lb=strlen(b+1);
  
  ne[1]=0;
  for(int i=2,j=0; i<=lb; i++){
    while(j && b[i]!=b[j+1]) j=ne[j];
    if(b[i]==b[j+1]) j++;
    ne[i]=j;
  }
  
  for(int i=1,j=0; i<=la; i++){
    while(j && a[i]!=b[j+1]) j=ne[j]; //失配前跳
    if(a[i]==b[j+1]) j++;             //匹配后移
    if(j==lb) printf("%d\n",i-lb+1);  //全配记录
  }
  
  for(int i=1;i<=lb;i++) printf("%d ",ne[i]);
  return 0;
}

 

// 哈希法 O(n)
#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
const int N=1e6+5;
const ull B=131;
string s,t;
int n,m;
ull f[N],g[N],b[N];

ull get1(int l,int r){
  return f[r]-f[l-1]*b[r-l+1];
}
ull get2(int l,int r){
  return g[r]-g[l-1]*b[r-l+1];
}
signed main(){
  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
  cin>>s>>t;
  n=s.size(),m=t.size();
  s=" "+s; t=" "+t;
  b[0]=1;
  
  for(int i=1; i<N; ++i) b[i]=b[i-1]*B;
  for(int i=1; i<=n; ++i) f[i]=f[i-1]*B+s[i];
  for(int i=1; i<=m; ++i) g[i]=g[i-1]*B+t[i];
  for(int i=1; i<=n-m+1; ++i)
    if(get1(i,i+m-1)==g[m]) cout<<i<<'\n';
  
  cout<<0<<' ';
  for(int i=2,j=0; i<=m; ++i){
    while(j>=0 && get2(1,j+1)!=get2(i-j,i)) j--;
    j++;
    cout<<j<<' ';
  }
  return 0;
}

 

posted @ 2022-04-13 19:30  董晓  阅读(4284)  评论(0)    收藏  举报