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\n",ans);
    }
    return 0;
}

HDU 1403 Longest Common Substring(后缀数组,最长公共子串),布布扣,bubuko.com

时间: 2024-12-29 12:34:39

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)的相关文章

HDU - 1403 - Longest Common Substring

先上题目: Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4010    Accepted Submission(s): 1510 Problem Description Given two strings, you have to tell the length of the Long

HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", a

HDU 1403 Longest Common Substring(最长公共前缀)

http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意:给出两个字符串,求最长公共子串的长度. 思路: 刚开始学后缀数组,确实感觉很难,但是这东西很强大,所以必须要学会它,推荐罗穗骞大牛的论文. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #i

POJ 2217 (后缀数组+最长公共子串)

题目链接: http://poj.org/problem?id=2217 题目大意: 求两个串的最长公共子串,注意子串是连续的,而子序列可以不连续. 解题思路: 有个炒鸡快的O(n)的Manacher算法.不过只能求裸的最长公共和回文子串. 后缀数组解法是这类问题的模板解法. 对于n个串的最长公共子串,这要把这些串连在一起,中间用"$"这类的特殊符号分隔一下. 先求后缀数组,再求最长公共前缀,取相邻两个且属于不同串的sa的最大LCP即可. 原理就是:这样把分属两个串的LCP都跑了一遍,

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

hdu_1403_Longest Common Substring(后缀数组的应用)

题目链接:hdu_1403_Longest Common Substring 题意: 给你两个字符串,然你找最长的公共子串 题解: 后缀数组的经典应用,要找两个字符串的公共子串,那么就相当于找两个串的后缀的最长公共前缀,我们将两个字符串拼接在一起,中间插一个特殊字符 然后我们考虑height数组,height数组存的是排i和i-1的最长前缀,如果sa[i]和sa[i-1]在特殊字符的两边,那么这个height[i]记录的就是这两个串的最长 子串,然后扫一遍height数组更新一下答案就行了 1

hdu 2459 Maximum repetition substring(后缀数组)

题目链接:hdu 2459 Maximum repetition substring 题意: 让你找一个重复最多的子串,并且输出. 题解: 这个是论文题,看的cxlove的题解,不是很理解为什么这样就能完全找完,当作结论使吧. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 namespace suffixarray{ 5 #define FN(n) f

面试题[后缀数组]: 最长重复子串

题目:给定一个字符串,求出最长重复子串. 这个题目可以用后缀数组来解:对后缀数组排好序,这样重复的子串就在相邻的后缀中找就可以了.我的C++代码实现如下: class Solution { public: string LongestRepeatingSubstring(string str) { size_t len = str.size(); vector<string> SuffixArray(len); for (size_t i = 0; i < len; ++i) Suffi

[poj 2274]后缀数组+最长公共子序列

题目链接:http://poj.org/problem?id=2774 后缀数组真的太强大了,原本dp是n^2的复杂度,在这里只需要O(n+m). 做法:将两个串中间夹一个未出现过的字符接起来,然后做一次后缀数组,得到的height相邻两个排名的后缀,在串中的位置如果满足在分界符左右两侧,就更新最长公共前缀.最后得到的最大值就是最长公共子序列. #include<algorithm> #include<cstdio> #include<cstring> using na