• 字符串匹配--扩展KMP模板


    对于一个字符串 s 以及子串 t ,扩展KMP可以用来求 t 与 s 的每个子串的最长公共前缀 ext [ i ],当然,如果有某个 ext 值等于 t 串的长度 lent ,那么就说明从其对应的 i 开始的一个长 lent 的子串即为 t 串,因此可以同样线性地求出 s 串中的每个 t 子串的出现位置与出现顺序。

    首先感谢 xiaoxin 巨巨,基本是从他的模板上面理解而来的昂。

    这里是助于我理解的满满注释版: 

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e6+5;
     5 inline int max(int a,int b){return a>b?a:b;}
     6 
     7 int nxt[maxn],ext[maxn];
     8 char s[maxn],t[maxn];
     9 
    10 void EKMP(char s[],char t[],int lens,int lent){    //s为字母串,t为子串,并分别传入两串长度,ekmp是求t串与s串每个位置开头的最长公共前缀
    11     int i,j,p,l,k;
    12     nxt[0]=lent;j=0;    //t串自匹配,从t0开始的t的子串(即t串本身)与t串的最长公共前缀定为t串长度,j为已匹配完的位置,j+1即待匹配的位置
    13     while(j+1<lent&&t[j]==t[j+1])j++;    //先匹配t1开始的子串,若依次匹配直到失配
    14     nxt[1]=j;    //t1开始的子串与t串最长公共前缀长度即为j
    15     k=1;    //k为除t0外的最远匹配的开始字符,后续每次进行额外匹配就更新它
    16     for(i=2;i<lent;i++){    //i表示匹配从ti开始的子串与t串的最长公共前缀
    17         p=nxt[k]+k-1;    //p即为k所对应的最远失配位置,也是整个t串在自匹配过程中已经匹配到的位置
    18         l=nxt[i-k];
    19         if(i+l<p+1)nxt[i]=l;    //从ti开始已经确定匹配成功的结束位置与总匹配过的位置p比较,若结束位置小,则说明到i+l出已经失配,ti开始的最长公共前缀即为l,否则对超过p的部分进行匹配,直到失配并更新k
    20         else{
    21             j=max(0,p-i+1);
    22             while(i+j<lent&&t[i+j]==t[j])j++;
    23             nxt[i]=j;
    24             k=i;
    25         }
    26     }
    27 
    28     j=0;    //t与s的每个子串匹配,可以根据之前已经匹配过的s串的部分转化为t串与s中t的子串匹配,首先初始匹配位置赋为0
    29     while(j<lens&&j<lent&&s[j]==t[j])j++;    //先匹配s0开始的串和t串的最长公共前缀
    30     ext[0]=j;k=0;    //s0处的最长公共前缀即刚匹配完的j,将最长匹配到的位置对应的s0赋给k,之后进行与t串自匹配基本一样的操作,但是循环的从i=1开始,更新ext数组
    31     for(i=1;i<lens;i++){
    32         p=ext[k]+k-1;
    33         l=nxt[i-k];
    34         if(l+i<p+1)ext[i]=l;
    35         else{
    36             j=max(0,p-i+1);
    37             while(i+j<lens&&j<lent&&s[i+j]==t[j])j++;
    38             ext[i]=j;
    39             k=i;
    40         }
    41     }
    42 }

    这里是为了敲和复制用的并没有注释版:

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e6+5;
     5 inline int max(int a,int b){return a>b?a:b;}
     6 
     7 int nxt[maxn],ext[maxn];
     8 char s[maxn],t[maxn];
     9 
    10 void EKMP(char s[],char t[],int lens,int lent){
    11     int i,j,p,l,k;
    12     nxt[0]=lent;j=0;
    13     while(j+1<lent&&t[j]==t[j+1])j++;
    14     nxt[1]=j;
    15     k=1;
    16     for(i=2;i<lent;i++){
    17         p=nxt[k]+k-1;
    18         l=nxt[i-k];
    19         if(i+l<p+1)nxt[i]=l;
    20         else{
    21             j=max(0,p-i+1);
    22             while(i+j<lent&&t[i+j]==t[j])j++;
    23             nxt[i]=j;
    24             k=i;
    25         }
    26     }
    27 
    28     j=0;
    29     while(j<lens&&j<lent&&s[j]==t[j])j++;
    30     ext[0]=j;k=0;
    31     for(i=1;i<lens;i++){
    32         p=ext[k]+k-1;
    33         l=nxt[i-k];
    34         if(l+i<p+1)ext[i]=l;
    35         else{
    36             j=max(0,p-i+1);
    37             while(i+j<lens&&j<lent&&s[i+j]==t[j])j++;
    38             ext[i]=j;
    39             k=i;
    40         }
    41     }
    42 }
  • 相关阅读:
    centos 6 升级gcc
    linux fdisk 分区
    centos使用163的源
    工作流发布成功但不能自动启动
    可怕的断电
    FTP 之 550 permission denied
    Track & Trace
    AutoKey思想的應用(二)
    Windows登錄過程淺析
    snapshot.exe出現異常
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4515141.html
Copyright © 2020-2023  润新知