POJ2774 后缀数组,求两个字符串的最长公共子串

1 学习别人的模板

2 列出两种情况

(1)代码一是两个字符串的最长公共子串poj2774

(2)代码二是假设求多个字符串中某两个字符串的最长公共子串

其中(2)没有题目,自己编的,为了便于重点理解:字符串组合时中间插入的字符对应的数应该是与输入的字符对应的ASC码不一样的数字,所以如果进行多个字符串的组合而插入多个间隔字符,那这些间隔字符应该也互相不同。

(

①代码一中 fir[k++]=31,对应代码二中 r[k++]=bian++;   数组名无所谓、注意的改变是31变为bian++。

②代码一中 da(r,k+1,31),对应代码二中 GetSa(r,k+1,bian);   函数名无所谓、注意的改变是31变为bian

)

3

注意,len是字符串实际长度(不补0的情况下):sa[],下标是该后缀的名次(1到len),值是该后缀的首字符在字符串中的位置(0到len-1);rank_[],下标是该后缀首字符在字符串中的位置(0到len-1),值是该后缀的名次(1到len);heigh[],下标是该后缀的名次(1到len),值是sa[i]与sa[i-1]的公共前缀长度,且heigh[1]是第一名次的后缀与第零名次后缀的公共前缀长度,因为第零名次后缀不存在所以heigh[1]也没有意义。

4

除了拿出来的几个函数,注意代入函数的语句:

da(r,k+1,31);//注意K+1
calHeight(r,k);

5

代码一:

#include<iostream>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int MAX = 200050;
char fir[MAX],sec[MAX];
int sa[MAX], rank[MAX], height[MAX];
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];

int cmp(int *r, int a, int b, int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}

void da(int *r, int n, int m)            //  倍增算法0(nlgn)。
{
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i ++) wd[i] = 0;
    for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
    for(i = 1; i < m; i ++) wd[i] += wd[i-1];
    for(i = n-1; i >= 0; i --) sa[-- wd[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 ++) wd[i] = 0;
        for(i = 0; i < n; i ++) wd[wv[i]] ++;
        for(i = 1; i < m; i ++) wd[i] += wd[i-1];
        for(i = n-1; i >= 0; i --) sa[-- wd[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 ++;
        }
    }
}

void calHeight(int *r, int n)            //  求height数组。
{
    int i, j, k = 0;
    for(i = 1; i <= n; i ++) rank[sa[i]] = i;
    for(i = 0; i < n; height[rank[i ++]] = k)
    {
        for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
    }
}
int main()
{
    int r[MAX];
    int len1,len2,k,maxx;
    while(~scanf("%s %s",fir,sec)){
        len1=strlen(fir);
        len2=strlen(sec);
        k=0;
        maxx=0;
        for(int i=0;i<len1;i++) r[k++]=fir[i]-'a'+1;
        fir[k++]=31;
        for(int i=0;i<len2;i++) r[k++]=sec[i]-'a'+1;
        sec[k]=0;

        da(r,k+1,31);//注意K+1
        calHeight(r,k);
        for(int i=2;i<k;i++){
            if(height[i]>maxx){
                if((sa[i-1]<len1&&sa[i]>len1)||(sa[i]<len1&&sa[i-1]>len1))
                    maxx=height[i];
            }
        }
        cout<<maxx<<endl;
    }
    return 0;
}

6

代码二


input::

3
aabbaabb
abbababb
bbbbbabb

0


output::

4

abba


#include<iostream>
#include<cstring>
#include <stdio.h>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;

//r[] 下标是字符位置从0开始;s[] 下标是名次从1开始、值是首字符位置从0开始;heigh[] 下标是名次从1开始、值是第i个名次的后缀和第i-1个名次的后缀的最长公共前缀长度(且heigh[1]没有意义);rank[] 下标是首字符位置从0开始、值是名次从1开始。
const int MAX = 800050;
char fir[MAX];
char scan[MAX];
int r[MAX];
int len[5000];
int sa[MAX], rank[MAX], height[MAX];
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];
int cmp(int *r, int a, int b, int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}
void GetSa(int *r, int n, int m)            //  倍增算法0(nlgn)。
{
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i ++) wd[i] = 0;
    for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
    for(i = 1; i < m; i ++) wd[i] += wd[i-1];
    for(i = n-1; i >= 0; i --) sa[-- wd[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 ++) wd[i] = 0;
        for(i = 0; i < n; i ++) wd[wv[i]] ++;
        for(i = 1; i < m; i ++) wd[i] += wd[i-1];
        for(i = n-1; i >= 0; i --) sa[-- wd[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 ++;
        }
    }
}
void GetHeight(int *r, int n)            //  求height数组。
{
    int i, j, k = 0;
    for(i = 1; i <= n; i ++) rank[sa[i]] = i;
    for(i = 0; i < n; height[rank[i ++]] = k)
    {
        for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
    }
}
int main()
{
    int t;

    while(~scanf("%d",&t)&&t){
        int k=0;
        int len_k=0;
        int bian=30;
        char com;
        char temp=getchar();
        for(int i=1;i<=t;i++){
            while(scanf("%c",&com)){
                if(com!='\n') r[k++]=com-'a'+1;
                else {
                    r[k++]=bian++;
                    len[len_k++]=k-1;
                    break;
                }
            }
        }
        fir[k]=0;
        GetSa(r,k+1,bian);
        GetHeight(r,k);
        int maxx=0;
        int tem=0;
        for(int i=2;i<k;i++){
            if(height[i]>maxx){
                for(int j=0;j<len_k;j++){
                    if((sa[i]>len[j]&&sa[i-1]<len[j])||(sa[i-1]>len[j]&&sa[i]<len[j])){
                        maxx=height[i];
                        tem=i;
                    }
                }
            }
        }
        cout<<maxx<<endl;
        cout<<sa[tem]<<endl;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值