zoukankan      html  css  js  c++  java
  • HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

    hdu题目

    poj题目

    参考了 罗穗骞的论文《后缀数组——处理字符串的有力工具》

    题意:求两个序列的最长公共子串

    思路:后缀数组经典题目之一(模版题)

    //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置。简单的记忆就是“排第几的是谁”。
    //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次。则 若 sa[i]=j,则 rank[j]=i。简单的记忆就是“你排第几”。
    //对于 后缀数组sa 与 名次数组rank ,有rank[ sa[i] ]=i (这是很重要的一点,通过sa与rank的关系可以求出后缀数组)
    //height 数组: 定义height[i]=suffix(sa[i-1]) 和 suffix(sa[i]) 的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。
    
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    #define maxn 200010
    int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
    int cmp(int *r,int a,int b,int l)
    {return r[a]==r[b]&&r[a+l]==r[b+l];}//yuan lai zhi qian ba zhe li de l cuo dang cheng 1 le ...
    void da(int *r,int *sa,int n,int m)
    {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++)ws[i]=0;
        for(i=0;i<n;i++)ws[x[i]=r[i]]++;
        for(i=1;i<m;i++)ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
        for(j=1,p=1;p<n;j*=2,m=p)
        {
            for(p=0,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<n;i++)wv[i]=x[y[i]];
            for(i=0;i<m;i++)ws[i]=0;
            for(i=0;i<n;i++)ws[wv[i]]++;
            for(i=1;i<m;i++)ws[i]+=ws[i-1];
            for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? (p-1):p++;
        }
    }
    int rankk[maxn],height[maxn];
    void calheight(int *r,int *sa,int n)
    {
        int i,j,k=0;
        for(i=1;i<=n;i++)rankk[sa[i]]=i;
        for(i=0;i<n;height[rankk[i++]]=k)
            for(k? k--:0,j=sa[rankk[i]-1];r[i+k]==r[j+k];k++);
    }
    int RMQ[maxn];
    int mm[maxn];
    int best[20][maxn];
    void initRMQ(int n)
    {
        int i,j,a,b;
        for(mm[0]=-1,i=1;i<=n;i++)
            mm[i]=((i&(i-1))==0) ? mm[i-1]+1:mm[i-1];
        for(i=1;i<=n;i++)best[0][i]=i;
        for(i=1;i<=mm[n];i++)
            for(j=1;j<=n+1-(1<<i);j++)
            {
                a=best[i-1][j];
                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)
    {
        int t;
        a=rankk[a]; b=rankk[b];
        if(a>b) {t=a;a=b;b=t;}
        return (height[askRMQ(a+1,b)]);
    }
    
        char s[maxn];
        int r[maxn],sa[maxn];
    int main()
    {
        while(scanf("%s",s)!=EOF)
        {
            int len1=strlen(s);
            s[len1]='0';//yin wei bu ce ng chu xian ,suo yi bu yong dan xin ying xiang jie guo
            scanf("%s",s+len1+1);
            int len2=strlen(s);
    
            for(int i=0;i<len2;i++)r[i]=s[i];//r[i]biao shi pai de shi di ji
            r[len2]=0;//ji shu pai xu shi de xu yao ,zui hou yi ge jia she wei zui xiao
    
            da(r,sa,len2+1,130);
            calheight(r,sa,len2);
            int ans=0;
            //bian li height shu zu, cong di 2 ge kai shi (xia biao shi cong 1 kai shi de )
            for(int i=2;i<=len2;i++)
            {
                if(height[i]>ans)
                {
                    if((len1<sa[i]&&len1>sa[i-1])||(len1>sa[i]&&len1<sa[i-1]))
                        ans=height[i];
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    leetcode第9题判断回文数
    leetcode整数反转第七题
    leetcode刷题两数之和
    找工作之旅
    C#和.Ne学习第五天
    C#和.Ne学习第四天
    C#和.Ne学习第三天
    C#和.Ne学习第二天
    C#和.Ne学习第一天
    从今天开始正事学习C#和.Net了
  • 原文地址:https://www.cnblogs.com/laiba2004/p/3920622.html
Copyright © 2011-2022 走看看