1. 程式人生 > 實用技巧 >LCS - Longest Common Substring

LCS - Longest Common Substring

SP1811 LCS - Longest Common Substring

用 sam 進行字串匹配,建 s 的 sam,然後用 t 在 s 的 sam 上進行匹配,匹配過程中,沿著 Next 轉移往下走,如果失配,則沿著 link 連結往上跳,因為 link 連結是該節點的字尾,所以這樣跳就不會有遺漏,而且均攤下來跳字尾連結的總複雜度為\(O(n)\)因此不會超時。

// Created by CAD
#include <bits/stdc++.h>
using namespace std;

const int maxn=(2e5+5e4+5)*2;
namespace sam{
    int len[maxn],link[maxn],Next[maxn][26];
    int sz,last;
    void init(){                //記得初始化
        sz=last=0;
        len[0]=0,link[0]=-1;
    }
    void insert(char c){        //插入字元
        int now=++sz;
        len[now]=len[last]+1;
        int p=last;
        while(~p&&!Next[p][c-'a']){
            Next[p][c-'a']=now;
            p=link[p];
        }
        if(p==-1) link[now]=0;
        else{
            int q=Next[p][c-'a'];
            if(len[p]+1==len[q]) link[now]=q;
            else{
                int clone=++sz;
                len[clone]=len[p]+1;
                memcpy(Next[clone],Next[q],sizeof(Next[q]));
                link[clone]=link[q];
                while(~p&&Next[p][c-'a']==q){
                    Next[p][c-'a']=clone;
                    p=link[p];
                }
                link[q]=link[now]=clone;
            }
        }
        last=now;
    }
    int solve(char *s,char *t){
        int ans=0;
        int op=0,last=-1;
        int slen=strlen(s),tlen=strlen(t);
        int now=0;
        while(op<tlen){
            int temp=0;
            while(op<tlen&&Next[now][t[op]-'a']){//如果匹配則沿著轉移走下去
                now=Next[now][t[op]-'a'];
                temp=op-last;
                ans=max(ans,temp);
                op++;
            }
            if(temp==0) op++,last++;
            while(~link[now]&&!Next[now][t[op]-'a'])
                //一旦失配,則沿著字尾連結往上跳,直到跳到0或者再次匹配
                now=link[now];
            	last+=temp-len[now];
        }
        return ans;
    }
}

char s[maxn],t[maxn];
int main() {
    sam::init();
    scanf("%s%s",s,t);
    int slen=strlen(s);
    for(int i=0;i<slen;++i) sam::insert(s[i]);
    printf("%d\n",sam::solve(s,t));
    return 0;
}