HDU 1403 字符串 后缀数组 只能说勉强会用后缀数组了

Longest Common Substring

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3045    Accepted Submission(s): 1078


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", and the length is 3.
 

Input
The input contains several test cases. Each test case contains two strings, each string will have at most 100000 characters. All the characters are in lower-case.

Process to the end of file.
 

Output
For each test case, you have to tell the length of the Longest Common Substring of them.
 

Sample Input
  
  
banana cianaic
 

Sample Output
  
  
3
 

Author
Ignatius.L
 

关于后缀数组。请详细看这里  http://blog.csdn.net/jokes000/article/details/7839686

后缀数组套用模板。直接计算出suffix(i)的排序,然后调用height数组计算字符串最大的相同。

最后计算时,因为height[i]=height[sa[i]] 跟 height[sa[i]-1] 的公共前缀的数目 ,需要通过sa[i-1]跟sa[i]判断是否来自于不同的字符串。通过中间len(第一个字符串当中间值来比较)

/*
 * @author ipqhjjybj
 * @date  20130707
 *
 */

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;

#define clr(x) memset(x,0,sizeof(x))
#define MAXN 200003
int cmp(int *r,int a,int b,int l){
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
int wa[MAXN],wb[MAXN],wv[MAXN],wss[MAXN];
//call da(s,sa,len,300) 来计算,300这个值有点太大了。只需要大于最大的字符的ASCII值即可
void da(char *r,int *sa,int n,int m){
    //后缀数组sa:将s的n个后缀从小到大排序后将
    //排序后的后缀的开头位置 顺次放入sa中,
    //则sa[i]储存的是排第i大的后缀的开头位置。
    //简单的记忆就是“排第几的是谁”。
    clr(wa),clr(wb),clr(wv),clr(wss);//是x排序,wb是y排序,wss基数排序,wv只是暂时存储
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++)wss[i]=0;//初始化,wss[i]表示i字面值的数的个数
    for(i=0;i<n;i++)wss[x[i]=r[i]]++;//x指代wa , 计数排序。如果数据过大则采用快速排序
    for(i=1;i<m;i++)wss[i]+=wss[i-1];//加上排前面的数目,就是目前的排序位置
    for(i=n-1;i>=0;i--)sa[--wss[x[i]]]=i;//这里最好不要写成i=0,你可以试着打印aaaa排序后的结果看下
    for(j=1,p=1;p<n;j<<=1,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]]; //wv就是每次暂时存储的功能。
        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--)sa[--wss[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++;
    }
    return;
}
int rank[MAXN],height[MAXN];
//h[i]=height[rank[i]]
//h[i]≥h[i-1]-1
void calheight(char *r,int *sa,int n){
    int i,j,k;
    clr(rank),clr(height);
    for(i=1;i<n;i++)rank[sa[i]]=i;
    for(k=i=0;i<n;height[rank[i++]]=k)
        for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++)
            ;
    return;
}
char s[MAXN];
int sa[MAXN];
int main(){
    int len1,len2,i,j,ans;
    //freopen("1403.in","r",stdin);
    while(scanf("%s",s)!=EOF){
        s[len1=strlen(s)]='#';
        scanf("%s",s+len1+1);
        len2=strlen(s);
        da(s,sa,len2,300);
        calheight(s,sa,len2);
        ans=0;
        for(i=1;i<len2;i++){
            if(height[i]>ans)
                if((sa[i-1]<(len1)&&sa[i]>(len1))||
                   (sa[i]<(len1)&&sa[i-1]>(len1)))
                   ans=height[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

勉强会用模板了。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值