SPOJ - LCS 后缀自动机 Longest Common Substring

A string is finite sequence of characters over a non-empty finite set Σ.

In this problem, Σ is the set of lowercase letters.

Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.

Now your task is simple, for two given strings, find the length of the longest common substring of them.

Here common substring means a substring of two or more strings.

Input
The input contains exactly two lines, each line consists of no more than 250000 lowercase letters, representing a string.

Output
The length of the longest common substring. If such string doesn’t exist, print “0” instead.

Example
Input:
alsdfkjfjkdsal
fdjskalajfkdsla

Output:
3
Notice: new testcases added

题意:给出两个串,问这两个串s,t的最长公共子串,
做法1:建两个自动机,然后dfs查找最长的公共子串,注意记忆话搜索
做法2:用s建立自动机,利用mx数组,mx数组代表当前节点的最长可以表示这个节点的子串长度。在匹配t的过程中,可以下一个节点的最长公共子串的长度小于等于前一个节点的最长公共子串的长度加1,那么如果当前节点有往第t[i]-‘a’的路径,那么长度加1;
否则利用pre数组,查找pre[p]是否含有走向t[i]-‘a’的路径,当前匹配长度是mx[p](第一个含有走向t[i]-‘a’的祖先)+1;

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 3e5;
char st[N];
int d[N*2];
struct SAM{
    int pre[20*N],nex[20*N][26],mx[20*N],last,top;
    int ed[2*N];
    void init(){
        top = 2;
        last = 1;
        memset(nex[1],0,sizeof(nex[1]));
    }
    int newnode(int x){
        //cout <<"!!!" << top << endl;
        mx[top] = x;
        for(int i = 0;i < 26;i ++) nex[top][i] = 0;
        return top ++;
    }
    void add(int x){
        int np = newnode(mx[last]+1);
        int p = last;
        while(p && nex[p][x] == 0) {
            nex[p][x] = np;
            //ed[np] = min(ed[np],ed[last]+1);
            p = pre[p];
        }
        if(!p){
            pre[np] = 1;
        }
        else{
            int q = nex[p][x];
            if(mx[q] == mx[p]+1){
                pre[np] = q;
            }
            else {
                int nq = newnode(mx[p]+1);
                for(int i = 0;i < 26;i ++) nex[nq][i] = nex[q][i];
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;
                while(p && nex[p][x] == q){
                    //ed[nq] = min(ed[nq],last+1);
                    nex[p][x] = nq;
                    p = pre[p];
                }
            }
        }
        last = np;
    }
    int get(int x,int y){
        return nex[x][y];
    }

}sa1;


int main(){
    sa1.init();
    scanf("%s",st);
    int len = strlen(st);
    for(int i = 0;i < len; i++) sa1.add(st[i]-'a');
    scanf("%s",st);
    len =strlen(st);
    int p = 1;
    int ans = 0;
    int nl = 0;
    for(int i = 0;i < len;i ++){
        //cout << p << ' '<<st[i] << ' '<< sa1.nex[p][st[i]-'a']<<endl;
        if(sa1.nex[p][st[i]-'a']){
            nl ++;
            p = sa1.nex[p][st[i]-'a'];
        }
        else{
            while(p && sa1.nex[p][st[i]-'a']==0){
                p = sa1.pre[p];
            }
            //cout <<"!!!!" << p << endl;
            if(p == 0) p=1,nl=0;
            else{
                nl = sa1.mx[p]+1;
                p = sa1.nex[p][st[i]-'a'];

            }
        }
        //cout << "###" << p << ' ' << nl << endl;
        ans = max(ans,nl);
    }
    printf("%d\n",ans);
    return 0;
}
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 3e5;
char st[N];
int d[N*2];
struct SAM{
    int pre[20*N],nex[20*N][26],mx[20*N],last,top;
    int ed[2*N];
    void init(){
        top = 2;
        last = 1;
        memset(nex[1],0,sizeof(nex[1]));
    }
    int newnode(int x){
        //cout <<"!!!" << top << endl;
        mx[top] = x;
        for(int i = 0;i < 26;i ++) nex[top][i] = 0;
        return top ++;
    }
    void add(int x){
        int np = newnode(mx[last]+1);
        int p = last;
        while(p && nex[p][x] == 0) {
            nex[p][x] = np;
            //ed[np] = min(ed[np],ed[last]+1);
            p = pre[p];
        }
        if(!p){
            pre[np] = 1;
        }
        else{
            int q = nex[p][x];
            if(mx[q] == mx[p]+1){
                pre[np] = q;
            }
            else {
                int nq = newnode(mx[p]+1);
                for(int i = 0;i < 26;i ++) nex[nq][i] = nex[q][i];
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;
                while(p && nex[p][x] == q){
                    //ed[nq] = min(ed[nq],last+1);
                    nex[p][x] = nq;
                    p = pre[p];
                }
            }
        }
        last = np;
    }
    int get(int x,int y){
        return nex[x][y];
    }

}sa1,sa2;

int dfs(int x,int y){
    //cout << x << ' ' << y << endl;
    if(d[x]) return d[x];
    int ret = 0;
    for(int i = 0;i < 26;i ++){
        if(sa1.nex[x][i] && sa2.nex[y][i]) ret = max(ret,dfs(sa1.nex[x][i],sa2.nex[y][i]));
    }
    return d[x] = ret+1;
}

int main(){
    sa1.init();
    scanf("%s",st);
    int len = strlen(st);
    for(int i = 0;i < len;i ++) sa1.add(st[i]-'a');
    sa2.init();
    scanf("%s",st);
    len = strlen(st);
    for(int i = 0;i < len;i ++)sa2.add(st[i]-'a');
    /*for(int i = 0;i < sa1.last; i++)
    for(int j = 0;j < 26;j ++){
        if(sa1.nex[i][j]) cout <<i << ' '<< sa1.nex[i][j] << ' '<< char(j+'a')<<endl;
    }
    for(int i = 0;i < sa2.last; i++)
    for(int j = 0;j < 26;j ++){
        if(sa2.nex[i][j]) cout <<i << ' '<< sa2.nex[i][j] << ' '<< char(j+'a')<<endl;
    }*/
    int ans = dfs(1,1);
    printf("%d\n",ans-1);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81236083