• kmp算法:
    模式串在主串中出现首次位置 以及出现次数

    //模式串在主串中出现首次位置 以及出现次数
    #include <bits/stdc++.h>
    using namespace std;
    const int maxx = 100010;
    int next[maxx];
    char s1[maxx],s2[maxx];
    int len1,len2;
    void getnext()
    {
      int j=0;
      int k=-1;
      next[0] = -1;
      while(j < len2)
          if(k == -1 || s2[j] == s2[k])
              next[++j] = ++k;
          else
              k = next[k];
    }
    //返回模式串s2在主串s1首次出现的位置 返回的位置从0开始的
    int kmp_index()
    {
      int i=0,j=0;
      getnext();
      while(i < len1 && j < len2)
      {
          if(j == -1 || s1[i] == s2[j])
              i++,j++;
          else
              j = next[j];
      }
      if(j == len2)
          return i- len2;
      return -1;
    }
    //返回模式串在主串出现的次数
    int kmp_count()
    {
      int ans = 0;
      int i,j=0;
      if(len1 == 1 && len2 == 1)
      {
          if(s1[0] == s2[0])
              return 1;
          return 0;
      }
      getnext();
      for(i=0;i<len1;i++)
      {
          while(j > 0 && s1[i] != s2[j])
              j = next[j];
          if(s1[i] == s2[j])
              j++;
          if(j == len2)
          {
              ans++;
              cout<<"j = "<<j<<endl;
              j = next[j];
          }
      }
      return ans;
    }
    int main()
    {
      int t;
      cin>>t;
      while(t--)
      {
          cin>>s1>>s2;
          len1 = strlen(s1);
          len2 = strlen(s2);
          cout<<"模式串s2在主串s1中首次出现的位置是 "<<kmp_index()<<endl;
          cout<<"模式串s2在主串s1中出现的次数是 "<<kmp_count()<<endl;
      }
      return 0;
    }
  • 扩展KMP算法:
    定义母串S和子串T,S的长度为n,T的长度为m;
    求 字符串T 与 字符串S的每一个后缀 的最长公共前缀;

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define ll long long
    const int MAX=1000010; //字符串长度最大值
    int next1[MAX],extend[MAX];
    char a[MAX],b[MAX];
    //预处理计算Next数组
    void getNext(char str[])
    {
      int i=0,j,po,len=strlen(str);
      next1[0]=len; //初始化next[0]
      while(str[i]==str[i+1] && i+1<len) i++; next1[1]=i; //计算next[1]
      po=1; //初始化po的位置
      for(i=2;i<len;i++)
      {
          if(next1[i-po]+i < next1[po]+po) //第一种情况,可以直接得到next[i]的值
              next1[i]=next1[i-po];
          else //第二种情况,要继续匹配才能得到next[i]的值
          {
              j = next1[po]+po-i;
              if(j<0) j=0; //如果i>po+next[po],则要从头开始匹配
              while(i+j<len && str[j]==str[j+i]) j++; next1[i]=j;
              po=i; //更新po的位置
          }
      }
    }
    //计算extend数组
    void EXKMP(char s1[],char s2[])
    {
      int i=0,j,po,len=strlen(s1),l2=strlen(s2);
      getNext(s2); //计算子串的next数组
      while(s1[i]==s2[i] && i<l2 && i<len) i++; extend[0]=i;
      po=0; //初始化po的位置
      for(i=1;i<len;i++)
      {
          if(next1[i-po]+i < extend[po]+po) //第一种情况,直接可以得到extend[i]的值
              extend[i]=next1[i-po];
          else //第二种情况,要继续匹配才能得到extend[i]的值
          {
              j = extend[po]+po-i;
              if(j<0) j=0; //如果i>extend[po]+po则要从头开始匹配
              while(i+j<len && j<l2 && s1[j+i]==s2[j]) j++; extend[i]=j;
              po=i; //更新po的位置
          }
      }
    }
    int main()
    {
      int t;
      scanf("%d",&t);
      while(t--)
      {
          memset(extend,0,sizeof(extend));
          memset(next1,0,sizeof(next1));
          scanf("%s%s",a,b);
          int l = strlen(a);
          EXKMP(a,b);
          for(int i=0;i<l;i++){
              printf("%d ",extend[i]);
          }
      }
      return 0;
    

}

```