• 后缀数组


    先写一个在线的多模字符串匹配

    O(m+logn)的,按照https://wenku.baidu.com/view/cd7db304e87101f69e31953e.html的思想,很难写

    没地方交啊

    只能找出是否出现,不能找出出现了几次

    要找出现的次数,大概就是二分第一个出现的位置和最后一个出现的位置吧?不确定能不能写

    拍了一会没出错,先当做对的好了

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<string>
      4 using namespace std;
      5 string str[1000100],txt;
      6 int n;
      7 namespace SA
      8 {
      9     int n,p,m=128,sa[1000100],t1[1000100],t2[1000100],cnt[1000100],*x=t1,*y=t2;
     10     int *height=t2,*rk=t1;
     11     int st[1000100][21],log2x[1000100],lft[21];
     12     const int log2n=20;
     13     void build()
     14     {
     15         int i,k;
     16         n=txt.length();
     17         for(i=0;i<n;i++)    cnt[x[i]=txt[i]]++;
     18         for(i=1;i<m;i++)    cnt[i]+=cnt[i-1];
     19         for(i=n-1;i>=0;i--)    sa[--cnt[x[i]]]=i;
     20         for(k=1;k<=n;k<<=1)
     21         {
     22             p=0;
     23             for(i=n-k;i<n;i++)    y[p++]=i;
     24             for(i=0;i<n;i++)    if(sa[i]>=k)    y[p++]=sa[i]-k;
     25             for(i=0;i<m;i++)    cnt[i]=0;
     26             for(i=0;i<n;i++)    cnt[x[y[i]]]++;
     27             for(i=1;i<m;i++)    cnt[i]+=cnt[i-1];
     28             for(i=n-1;i>=0;i--)    sa[--cnt[x[y[i]]]]=y[i];
     29             swap(x,y);p=0;
     30             x[sa[0]]=0;
     31             for(i=1;i<n;i++)
     32                 x[sa[i]]=y[sa[i]]==y[sa[i-1]]
     33                 &&(sa[i]+k<n?y[sa[i]+k]:0)==(sa[i-1]+k<n?y[sa[i-1]+k]:0)
     34                 ?p:++p;
     35             if(p>=n)    break;
     36             m=p+1;
     37         }
     38         for(i=0;i<n;i++)    rk[sa[i]]=i;
     39         for(i=0,k=0;i<n;i++)
     40         {
     41             if(k)    k--;
     42             if(rk[i])
     43                 while(sa[rk[i]-1]+k<n&&i+k<n&&txt[sa[rk[i]-1]+k]==txt[i+k])    k++;
     44             height[rk[i]]=k;
     45         }
     46         lft[0]=1;for(i=1;i<=log2n;i++)    lft[i]=lft[i-1]<<1;
     47         log2x[1]=k=0;
     48         for(i=2;i<=1000000;i++)
     49         {
     50             if(i>=lft[k+1])    ++k;
     51             log2x[i]=k;
     52         }
     53         for(i=0;i<n;i++)    st[i][0]=height[i];
     54         for(k=1;k<=log2n;k++)
     55             for(i=0;i<n-lft[k]+1;i++)
     56                 st[i][k]=min(st[i][k-1],st[i+lft[k-1]][k-1]);
     57     }
     58     int lcp(int l,int r)
     59     {
     60         if(l==r)    return n-l;
     61         l=rk[l];r=rk[r];if(l>r) swap(l,r);
     62         l++;int k=log2x[r-l+1];
     63         return min(st[l][k],st[r-lft[k]+1][k]);
     64     }
     65     int lcp(const char *x,int l)
     66     {
     67         int ans=0;
     68         while(*x&&l<n&&*x==txt[l])    ++x,++l,++ans;
     69         return ans;
     70     }
     71     bool find(const string &x)
     72     {
     73         int l=0,r=n-1,t,mid,mmatch=lcp(x.c_str(),0),mpos=0,m=x.length(),state;
     74         while(r>l)
     75         {
     76             mid=(l+r)/2;t=lcp(sa[mid],mpos);
     77             if(t<mmatch)
     78             {
     79                 if(x[t]<txt[sa[mid]+t])    state=-1;
     80                 //else if(x[t]==txt[sa[mid]+t])    state=0;
     81                 else state=1;
     82             }
     83             else
     84             {
     85                 mpos=sa[mid];
     86                 while(mmatch<m&&mmatch+mpos<n&&x[mmatch]==txt[mmatch+mpos])    mmatch++;
     87                 if(mmatch==m)    state=0;
     88                 else if(x[mmatch]<txt[mmatch+mpos])    state=-1;
     89                 else if(x[mmatch]>txt[mmatch+mpos])    state=1;
     90             }
     91             if(state<0)    r=mid-1;
     92             else if(state==0)    return 1;
     93             else l=mid+1;
     94         }
     95         return lcp(x.c_str(),sa[l])==m;
     96     }
     97 }
     98 int ans;
     99 int main()
    100 {
    101     int i;
    102     cin>>n;
    103     for(i=1;i<=n;i++)    cin>>str[i];
    104     cin>>txt;
    105     SA::build();
    106     //for(i=0;i<SA::n;i++)    cout<<SA::sa[i]+1<<' ';
    107     for(i=1;i<=n;i++)    ans+=SA::find(str[i]);
    108     cout<<ans;
    109     return 0;
    110 }

    另一份后缀数组模板

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 char s[1000100];
     6 int n;
     7 int sa[1000100],t1[1000100],t2[1000100],cnt[1000100];
     8 int *x=t1,*y=t2,m='z',p;
     9 int main()
    10 {
    11     int i,k;
    12     scanf("%s",s+1);n=strlen(s+1);
    13     for(i=1;i<=n;i++)    cnt[x[i]=s[i]]++;
    14     for(i=1;i<=m;i++)    cnt[i]+=cnt[i-1];
    15     for(i=n;i>=1;i--)    sa[cnt[x[i]]--]=i;
    16     for(k=1;k<=n;k<<=1)
    17     {
    18         //x[i]存上一轮中后缀i的rank
    19         p=0;
    20         for(i=n-k+1;i<=n;i++)    y[++p]=i;
    21         for(i=1;i<=n;i++)    if(sa[i]>k)    y[++p]=sa[i]-k;
    22         //y[i]暂存对第二关键字排序后的rank为i的后缀编号
    23         for(i=1;i<=m;i++)    cnt[i]=0;
    24         for(i=1;i<=n;i++)    cnt[x[y[i]]]++;
    25         for(i=1;i<=m;i++)    cnt[i]+=cnt[i-1];
    26         for(i=n;i>=1;i--)    sa[cnt[x[y[i]]]--]=y[i];
    27         
    28         swap(x,y);p=0;
    29         for(i=1;i<=n;i++)    x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
    30         if(p>=n)    break;
    31         m=p;
    32     }
    33     for(i=1;i<=n;i++)    printf("%d ",sa[i]);
    34     return 0;
    35 }

    nlog^2n构造简单代码

    inline bool cmp(int u,int v)
    {
        if(rank[u]!=rank[v]) return rank[u]<rank[v];
        int nu,nv;
        nu= (u+l>len?0:rank[u+l]);
        nv= (v+l>len?0:rank[v+l]);
        return nu<nv;
    }
     
    int main()
    {
        int i,j,k;
        scanf("%s",str+1);
        len=strlen(str+1);
        for(i=1; i<=len; i++)
        {
            rank[i]=str[i];
            st[i]=i;
        }
        for(l=1; l<=len; l<<=1)
        {
            sort(st+1,st+len+1,cmp);
            tmp[st[1]]=1;
            for(i=2; i<=len; i++)
            {
                tmp[st[i]]=tmp[st[i-1]]+cmp(st[i-1],st[i]);
            }
            for(i=1; i<=len; i++)
            {
                rank[i]=tmp[i];
            }
        }
    }
  • 相关阅读:
    三数之和
    167
    二分搜索树
    687
    索引堆
    二分查找 leetcode704
    leetcode 56合并区间 java
    leetcode 1046
    堆的数据结构java
    leetcode 493
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8658036.html
Copyright © 2020-2023  润新知