最长公共子串

最长公共子串

给出两个长度小于1e5的串,求它们的最长公共子串。

当然是用后缀数组辣,把两个串拼起来,中间加个@符号,再求最长重复子串,处理一下即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=2e5+5;

char s[maxn];
int n, orin, ans, m=maxn, sa[maxn], ht[maxn];
int *x, *y, *t, wa[maxn], wb[maxn], ws[maxn], wv[maxn];
bool cmp(int *r, int a, int b, int l){
    return r[a]==r[b]&&r[a+l]==r[b+l]; }
void Ssort(char *r){
    int i, j, p=0; x=wa; y=wb; m=maxn;
    memset(ws, 0, sizeof(ws));
    for (i=0; i<n; ++i) ++ws[x[i]=r[i]];
    for (i=1; i<m; ++i) ws[i]+=ws[i-1];
    for (i=0; i<n; ++i) sa[--ws[r[i]]]=i;
    for (j=1; j<n&&p<n; j<<=1, m=p+1){
        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[x[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];
        t=x; x=y; y=t; x[sa[0]]=1;
        for (p=1, i=1; i<n; ++i)
            x[sa[i]]=cmp(y, sa[i-1], sa[i], j)?p:++p;
    }
    for (i=0; i<n; ++i) --x[i]; p=0;
    for (i=0; i<n; ht[x[i++]]=p){
        if (!x[i]){ p=0; continue; }
        for (p?p--:0, j=sa[x[i]-1]; r[i+p]==r[j+p]&&i+p<n; ++p);
    }
    return;
}

int main(){
    scanf("%s", s); n=orin=strlen(s);  //s[orin]='@'
    s[n++]='@'; scanf("%s", s+n); n=strlen(s);
    Ssort(s);
    for (int i=1; i<n; ++i)
        if (sa[i]<orin&&sa[i-1]>orin
                ||sa[i]>orin&&sa[i-1]<orin)
            ans=max(ans, ht[i]);
    printf("%d
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/MyNameIsPc/p/9219549.html