zoukankan      html  css  js  c++  java
  • [模板] kmp

    本文基于https://blog.csdn.net/v_july_v/article/details/7041827和《算法竞赛入门经典训练指南》

    注意:有时可能会编译错误,因为next可能是关键字,此时改变一下next数组的名字就行了

    下面这个kmp可以求出模板串在文本串中第一个匹配的位置,也可以在return那改成记录位置最后结束时返回一个位置数组来得到所有匹配位置

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int amn=1e5+5;
     4 int next[amn];
     5 
     6 void GetNext(char *p,int next[]){
     7     int plen=strlen(p);
     8     next[0]=-1;               ///next是上一个字符对应的前缀等于后缀的最长长度
     9     int k=-1,j=0;             ///因为字符串下标从0开始,所以最长长度也是前缀最后一个字符的下一个字符的下标(index)(前缀与后缀相等的最长长度0对应第一个字符,1对应第2个...这样保证这一位之前的字符是匹配的(因为现在已经知道前缀与后缀匹配))
    10     while(j<plen-1){          ///k是上一个状态的next,若j==plen-1则此为是最后一个字符,其后没有字符,故不需求出下一个字符的next
    11         if(k==-1||p[j]==p[k]){///k==-1在前面判断为真就直接执行下一条语句而不会造成数组越界
    12             k++,j++;
    13             if(p[j]!=p[k])
    14                 next[j]=k;
    15             else              ///若p[j]==p[k]且p[j]!=s[i],则下次用p[k]匹配仍是失效的,故要用p[next[k]](若p[j]!=p[next[k]]来和s[i]匹配
    16                 next[j]=next[k];
    17         }
    18         else k=next[k];
    19     }
    20 }
    21 int kmp_search(char *s,char *p){
    22     int slen=strlen(s),plen=strlen(p);
    23     int i=0,j=0;
    24     while(i<slen&&j<plen){
    25         if(j==-1||s[i]==p[j])i++,j++;
    26         else j=next[j];
    27     }
    28     if(j==plen)return i-j;  ///这个可以求出模板串在文本串中第一个匹配的位置,也可以在return那改成记录位置最后结束时返回一个位置数组来得到所有匹配位置
    29     else return -1;
    30 }
    31 int main(){
    32     char s[]="hello",p[]="ll";
    33     GetNext(p,next);
    34     printf("pos: %d
    ",kmp_search(s,p));
    35 }

    下面这个kmp返回的是t与p最后一个不匹配的位置,用来去除t的后缀与p的前缀相同的部分(就是去重),同时在函数中减少了strlen的调用,这样在模板串比较多时不容易TLE
    例题参见 Codeforces 1200E
    http://codeforces.com/contest/1200/problem/E

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int amn=1e6+5;
     4 char ans[amn],in[amn];
     5 int nex[amn],len,tp;
     6 void getnex(char p[]){     ///不要在这调用strlen!!!,用已有的就好了,不然会T到自闭!!!
     7     nex[0]=nex[1]=0;
     8     for(int i=1;i<len;i++){
     9         int j=nex[i];
    10         while(j&&p[i]!=p[j])j=nex[j];
    11         nex[i+1]=p[i]==p[j]?j+1:0;
    12     }
    13 }
    14 int kmp(char t[],char p[]){     ///不要在这调用strlen!!!,用已有的就好了,不然会T到自闭!!!
    15     getnex(in);
    16     int j=0;
    17     for(int i=pos;i<tlen;i++){
    18         while(j&&p[j]!=t[i])j=nex[j];
    19         if(p[j]==t[i])j++;
    20     }
    21     return j;       ///这里返回的是t与p最后一个不匹配的位置,用来去除t的后缀与p的前缀相同的部分(就是去重),例题参见 Codeforces 1200E
    22 }
    23 int main(){
    24     cin>>t>>p;
    25     tlen=strlen(t),plen=strlen(p);  ///在这里调用strlen就行了,不然如果模板串太多的话调用太多strlen会TLE
    26 }
    27 /**
    28 返回的是t与p最后一个不匹配的位置,用来去除t的后缀与p的前缀相同的部分(就是去重),同时在函数中减少了strlen的调用,这样在模板串比较多时不容易TLE
    29 例题参见 Codeforces 1200E
    30 http://codeforces.com/contest/1200/problem/E
    31 **/
  • 相关阅读:
    CHIL-ORACLE-truncate 语法 清空表数据
    CHIL-ORACLE-复制表结构与复制表数据
    CHIL-ORACLE-伪列
    CHIL-ORACLE-给表插入数据
    CHIL-ORACLE-修改
    CHIL-ORACLE-创建同义词
    CHIL-ORACLE-创建默认约束
    CHIL-ORACLE-创建视图
    CHIL-ORACLE-检查约束(check)
    CHIL-ORACLE-主外键约束(primary key / foreign key)
  • 原文地址:https://www.cnblogs.com/Railgun000/p/11259943.html
Copyright © 2011-2022 走看看