1.kmp

/*
kmp
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

#define MAXN 1024//字符串长度

int _next[MAXN];

void GetNext(char t[]){//求next数组
    int j,k,len;
    j=0;//从0开始,首先求_next[1]
    k=-1;//比较指针
    _next[0]=-1;//初始值-1
    len=strlen(t);
    while(j<len){
        if(k==-1||t[j]==t[k]){//指针到头了,或者相等
            ++j;
            ++k;
            _next[j]=k;//此句可由优化替代
            /*优化(求匹配位置时可用)
            if(t[j]!=t[k])_next[j]=k;
            else _next[j]=_next[k];
            //*/
        }
        else k=_next[k];
    }
}

int KMPIndex(char s[],char t[]){//求子串首次出现在主串中的位置
    int i,j,lens,lent;
    i=j=0;
    lens=strlen(s);
    lent=strlen(t);

    while(i<lens&&j<lent){
        if(j==-1||s[i]==t[j]){
            ++i;
            ++j;
        }
        else j=_next[j];
    }
    if(j>=lent)return i-lent;
    else return -1;
}

int KMPCount(char s[],char t[]){//统计子串在主串中的出现次数,可重叠
    int i,j,lens,lent,cnt;
    i=j=0;
    lens=strlen(s);
    lent=strlen(t);
    cnt=0;

    while(i<lens){
        if(j==-1||s[i]==t[j]){
            ++i;
            ++j;
        }
        else j=_next[j];
        if(j==lent)++cnt;
    }
    return cnt;
}

void KMPCount2(char t[]){//统计单串中从某个位置以前有多少重复的串
    int i,lent,tmp;
    lent=strlen(t);

    for(i=2;i<=lent;++i){
        tmp=i-_next[i];//tmp是0...i-1这一串的最小循环节长度
        if(i%tmp==0&&i/tmp>1)
            printf("	位置:%d 个数:%d
",i,i/tmp);
    }
}

int main(){
    char str1[MAXN],str2[MAXN];
    int i,len2;
    printf("输入主串、子串:");
    while(~scanf("%s%s",str1,str2)){
        GetNext(str2);//求子串的next数组

        //输出next数组的值
        printf("next:");
        len2=strlen(str2);
        for(i=0;i<=len2;++i)
            printf("%d ",_next[i]);
        printf("
");

        printf("首次出现位置:%d
",KMPIndex(str1,str2));

        printf("子串在主串中的出现次数:%d
",KMPCount(str1,str2));

        printf("子串中的重复串:
");
        KMPCount2(str2);

        printf("输入主串、子串:");
    }
    return 0;
}
View Code

2.扩展kmp

/*
扩展kmp
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

#define MaxSize 1024

int _next[MaxSize],extend[MaxSize];

//扩展kmp
//next[i]:x[i...m-1]与x[0...m-1]的最长公公前缀
//extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀
void pre_EKMP(char x[],int m,int _next[]){//m长度
    _next[0]=m;
    int j=0;
    while(j+1<m&&x[j]==x[j+1])j++;
    _next[1]=j;
    int k=1;
    for(int i=2;i<m;i++){
        int p=_next[k]+k-1;
        int L=_next[i-k];
        if(i+L<p+1)_next[i]=L;
        else{
            j=max(0,p-i+1);
            while(i+j<m&&x[i+j]==x[j])j++;
            _next[i]=j;
            k=i;
        }
    }
}

void EKMP(char x[],int m,char y[],int n,int _next[],int extend[]){//x子串,m子串长度,y主串,n主串长度
    pre_EKMP(x,m,_next);
    int j=0;
    while(j<n&&j<m&&x[j]==y[j])j++;
    extend[0]=j;
    int k=0;
    for(int i=1;i<n;i++){
        int p=extend[k]+k-1;
        int L=_next[i-k];
        if(i+L<p+1)extend[i]=L;
        else{
            j=max(0,p-i+1);
            while(i+j<n&&j<m&&y[i+j]==x[j])j++;
            extend[i]=j;
            k=i;
        }
    }
}
/*
子串  :a b a b
主串  :a b a b a c
next  :4 0 2 0
extend:4 0 3 0 1 0
*/

int main(){
    char str1[32],str2[32];//子串,主串
    int i,len1,len2;//子串长度,主串长度
    scanf("%s%s",str1,str2);
    len1=strlen(str1);
    len2=strlen(str2);
    EKMP(str1,len1,str2,len2,_next,extend);
    for(i=0;i<len1;++i)
        printf("%d ",_next[i]);
    printf("
");
    for(i=0;i<len2;++i)
        printf("%d ",extend[i]);
    printf("
");

    return 0;
}
View Code

3.Manacher

/*
Manacher
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

//求最长回文子串
const int MAXN=110010;
char Ma[MAXN*2];
int Mp[MAXN*2];

void Manacher(char s[],int len){
    int l=0;
    Ma[l++]='$';
    Ma[l++]='#';
    for(int i=0;i<len;i++){
        Ma[l++]=s[i];
        Ma[l++]='#';
    }
    Ma[l]=0;
    int mx=0,id=0;
    for(int i=0;i<l;i++){
        Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
        while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;
        if(i+Mp[i]>mx){
            mx=i+Mp[i];
            id=i;
        }
    }
}
/*
abaaba
i:    0 1 2 3 4 5 6 7 8 9 10 11 12 13
Ma[i]:$ # a # b # a # a # b  #  a  #
Mp[i]:1 1 2 1 4 1 2 7 2 1 4  1  2  1
*/

char s[MAXN];
int main(){
    while(scanf("%s",s)==1){
        int len=strlen(s);
        Manacher(s,len);
        int ans=0;
        for(int i=0;i<2*len+2;i++)
            ans=max(ans,Mp[i]-1);
        printf("%d
",ans);
    }
    return 0;
}
View Code

4.ac自动机

/*
ac自动机模板
n个关键字,1段描述,求描述中出现了多少关键字
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

struct Trie{
    int next[500010][26],fail[500010],end[500010];
    int root,L;
    int newnode(){
        for(int i=0;i<26;i++)
            next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init(){
        L=0;
        root=newnode();
    }
    void insert(char buf[]){
        int len=strlen(buf);
        int now=root;
        for(int i=0;i<len;i++){
            if(next[now][buf[i]-'a']==-1)
                next[now][buf[i]-'a']=newnode();
            now=next[now][buf[i]-'a'];
        }
        end[now]++;
    }
    void build(){
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i<26;i++)
            if(next[root][i]==-1)
                next[root][i]=root;
            else{
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        while(!Q.empty()){
            int now=Q.front();
            Q.pop();
            for(int i=0;i<26;i++)
                if(next[now][i]==-1)
                    next[now][i]=next[fail[now]][i];
                else{
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int query(char buf[]){
        int len=strlen(buf);
        int now=root;
        int res=0;
        for(int i=0;i<len;i++){
            now=next[now][buf[i]-'a'];
            int temp=now;
            while(temp!=root){
                res+=end[temp];
                end[temp]=0;
                temp=fail[temp];
            }
        }
        return res;
    }
    void debug(){
        for(int i=0;i<L;i++){
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j=0;j<26;j++)
                printf("%2d",next[i][j]);
            printf("]
");
        }
    }
};

char buf[1000010];
Trie ac;

int main(){
    int T;
    int n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        ac.init();
        for(int i=0;i<n;i++){
            scanf("%s",buf);
            ac.insert(buf);
        }
        ac.build();
        scanf("%s",buf);
        printf("%d
",ac.query(buf));
    }
    return 0;
}
View Code

5.trie树(字典树)

c.动态开辟:

/*
trie树(字典树)
动态开辟
*/
#include<iostream>
#include<string.h>
using namespace std;

const int MAX=26;
struct Trie
{
    Trie *next[MAX];
    int v;   //根据需要变化,1代表无此单词,-1代表有此单词
};
Trie *root=new Trie;

void createTrie(char *str)
{
    int len = strlen(str);
    Trie *p = root, *q;
    for(int i=0; i<len; ++i)
    {
        int id = str[i]-'a';
        if(p->next[id] == NULL)
        {
            // q = (Trie *)malloc(sizeof(Trie));
            q = new Trie;
            q->v = 1;    //初始v==1
            for(int j=0; j<MAX; ++j)
                q->next[j] = NULL;
            p->next[id] = q;
        }
        p = p->next[id];
    }
    p->v = -1;   //若为结尾,则将v改成-1表示
}
int findTrie(char *str)
{
    int len = strlen(str);
    Trie *p = root;
    for(int i=0; i<len; ++i)
    {
        int id = str[i]-'a';
        p = p->next[id];
        if(p == NULL)   //若为空集,表示不存以此为前缀的串
            return 0;
        if(p->v == -1)   //字符集中已有串是此串的前缀
            return 1;
    }
    return 2;   //此串是字符集中某串的前缀
}
int deleteTrie(Trie* T)
{
    int i;
    if(T==NULL)
        return 0;
    for(i=0; i<MAX; i++)
    {
        if(T->next[i]!=NULL)
            deleteTrie(T->next[i]);
    }
    //free(T);
    delete(T);
    return 0;
}
int main()
{
    char str[20];
    int i;
    for(i=0; i<MAX; i++)
        root->next[i]=NULL;

    cout<<"输入串1:";
    cin>>str;
    createTrie(str);
    cout<<"输入串2:";
    cin>>str;
    cout<<findTrie(str)<<endl;
    return 0;
}
View Code

c2.静态数组:抽空补上。

6.后缀数组

c.DA

/*
后缀数组
DA
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

const int MAXN=20010;
int t1[MAXN],t2[MAXN],c[MAXN];
bool cmp(int *r,int a,int b,int l){
    return r[a]==r[b]&&r[a+l]==r[b+l];
}

void da(int str[],int sa[],int rank[],int height[],int n,int m){
    n++;
    int i,j,p,*x=t1,*y=t2;
    for(i=0;i<m;i++)c[i]=0;
    for(i=0;i<n;i++)c[x[i]=str[i]]++;
    for(i=1;i<m;i++)c[i]+=c[i-1];
    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(j=1;j<=n;j<<=1){
        p=0;
        for(i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[y[i]]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        if(p>=n)break;
        m=p;
    }
    int k=0;
    n--;
    for(i=0;i<=n;i++)rank[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k)k--;
        j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int rank[MAXN],height[MAXN];
int RMQ[MAXN];
int mm[MAXN];
int best[20][MAXN];
void initRMQ(int n){
    mm[0]=-1;
    for(int i=1;i<=n;i++)
        mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
    for(int i=1;i<=n;i++)best[0][i]=i;
    for(int i=1;i<=mm[n];i++)
        for(int j=1;j+(1<<i)-1<=n;j++){
            int a=best[i-1][j];
            int b=best[i-1][j+(1<<(i-1))];
            if(RMQ[a]<RMQ[b])best[i][j]=a;
            else best[i][j]=b;
        }
}

int askRMQ(int a,int b){
    int t;
    t=mm[b-a+1];
    b-=(1<<t)-1;
    a=best[t][a];b=best[t][b];
    return RMQ[a]<RMQ[b]?a:b;
}

int lcp(int a,int b){
    a=rank[a];b=rank[b];
    if(a>b)swap(a,b);
    return height[askRMQ(a+1,b)];
}
char str[MAXN];
int r[MAXN];
int sa[MAXN];

int main(){
    while(scanf("%s",str)==1){
        int len=strlen(str);
        int n=2*len+1;
        for(int i=0;i<len;i++)r[i]=str[i];
        for(int i=0;i<len;i++)r[len+1+i]=str[len-1-i];
        r[len]=1;
        r[n]=0;
        da(r,sa,rank,height,n,128);
        for(int i=1;i<=n;i++)RMQ[i]=height[i];
        initRMQ(n);
        int ans=0,st;
        int tmp;
        for(int i=0;i<len;i++){
            tmp=lcp(i,n-i);
            if(2*tmp>ans){
                ans=2*tmp;
                st=i-tmp;
            }
            tmp=lcp(i,n-i-1);
            if(2*tmp>ans){
                ans=2*tmp-1;
                st=i-tmp+1;
            }
        }
        str[st+ans]=0;
        printf("%s
",str+st);
    }
    return 0;
}
View Code

c2.DC3

/*
后缀数组
DC3
*/
#include<iostream>
#include<stdio.h>
using namespace std;

const int MAXN=2010;
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[MAXN*3],wb[MAXN*3],wv[MAXN*3],wss[MAXN*3];
int c0(int *r,int a,int b){
    return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];
}
int c12(int k,int *r,int a,int b){
    if(k==2)
        return r[a]<r[b]||(r[a]==r[b]&&c12(1,r,a+1,b+1));
    else return r[a]<r[b]||(r[a]==r[b]&&wv[a+1]<wv[b+1]);
}
void sort(int *r,int *a,int *b,int n,int m){
    int i;
    for(i=0;i<n;i++)wv[i]=r[a[i]];
    for(i=0;i<m;i++)wss[i]=0;
    for(i=0;i<n;i++)wss[wv[i]]++;
    for(i=1;i<m;i++)wss[i]+=wss[i-1];
    for(i=n-1;i>=0;i--)
        b[--wss[wv[i]]]=a[i];
}
void dc3(int *r,int *sa,int n,int m){
    int i,j,*rn=r+n;
    int *san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
    r[n]=r[n+1]=0;
    for(i=0;i<n;i++)if(i%3!=0)wa[tbc++]=i;
    sort(r+2,wa,wb,tbc,m);
    sort(r+1,wb,wa,tbc,m);
    sort(r,wa,wb,tbc,m);
    for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
        rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
    if(p<tbc)dc3(rn,san,tbc,p);
    else for(i=0;i<tbc;i++)san[rn[i]]=i;
    for(i=0;i<tbc;i++)if(san[i]<tb)wb[ta++]=san[i]*3;
    if(n%3==1)wb[ta++]=n-1;
    sort(r,wb,wa,ta,m);
    for(i=0;i<tbc;i++)wv[wb[i]=G(san[i])]=i;
    for(i=0,j=0,p=0;i<ta&&j<tbc;p++)
        sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
    for(;i<ta;p++)sa[p]=wa[i++];
    for(;j<tbc;p++)sa[p]=wb[j++];
}
void da(int str[],int sa[],int rank[],int height[],int n,int m){
    for(int i=n;i<n*3;i++)
        str[i]=0;
    dc3(str,sa,n+1,m);
    int i,j,k=0;
    for(i=0;i<=n;i++)rank[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k)k--;
        j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int main(){
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/gongpixin/p/5361058.html