S="yeshowmuchiloveyoumydearmotherreallyicannotbelieveit" T="yeaphowmuchiloveyoumydearmother"求N个最长为L的字符串的的LCS的方法大致可分为以下几类
作为最长公共子序列问题的简化,常规解法为动态规划(DP),参考代码如下。
int LCS(string S,string T){ if(S==""||T=="")return 0; if(S.length()>T.length())swap(S,T); int ls=S.length(),MAX=-1; int now=0,former=1; vector<vector<int>> memo(2,vector<int>(ls)); for(auto t:T){ memo[now][0]=(t==S[0]); for(int i=1;i<ls;++i){ if(S[i]!=t)memo[now][i]=0; else MAX=max(MAX,memo[now][i]=memo[former][i-1]+1); } swap(now,former); } return MAX; }
后缀数组SA[i]表示排名第i的后缀的位置,高度数组(LCP数组)Height[i]表示后缀SA[i]和SA[i-1]的最长公共前缀(Longest Common Prefix, LCP),简记为Height[i]=LCP(SA[i],SA[i-1]),详细介绍可参见后缀数组(Suffix Arrary) .求两个字符串S和T的最长公共子串,可以构造一个新串S+T,然后建立后缀数组,求出LCP数组。可以知道,最长公共前缀一定是出现在后缀数组中相邻的两个子串里的(否则越离越远,只可能更小)。利用这一点,我们找出满足sa[i]和sa[i+1]分属于S1,S2的串,然后对应的LCP数组中的最大值就是答案。下面给出了求两个字符串的LCS的代码,利用了后缀数组(Suffix Arrary)一文中给出的后缀树类(SA),SA有两个成员变量sa和height,分别为构造字符串S的后缀数组和高度数组。
int LCS(const string &S,const string &T) { string R=S+T; int len=R.size(),ls=S.size(),MAX=0; //构造后缀数组,第二个参数为构造SA的算法(如Prefix Doubling, DC3, SA-IS等) SA mySA(R,&SA::prefixDoubling); for(int i=0;i<len;++i) { if((mySA.sa[i]<ls)!=(mySA.sa[i+1]<ls))MAX=max(MAX,mySA.height[i]); } return MAX; }
为什么失配后要移向 par 呢?因为在状态 p 上失配说明该状态的 [min,max] 所表示字符串都不是 B 中的子串,但是比它们短的后缀仍有可能是 B 的子串,而 par 指针恰好指向了该状态的后缀。
#define N 200005 struct Node { int f,next[26],l; }G[N]; class SAM { char *st; int n,len,last,cnt; public: int MAX; SAM(string S):len(1),cnt(0),last(1),MAX(0) { st=(char*)malloc(S.size()); for(int i=0;i<S.size();++i)add(S[i]-'a'); last=1; } void add(int ch) { int i,x,p; G[++len].l=G[last].l+1; for(i=last;i&&!G[i].next[ch];i=G[i].f)G[i].next[ch]=len; p=G[i].next[ch],last=len,x=i; if(!x){G[1].next[ch]=len,G[len].f=1; return;} if(G[p].l==G[x].l+1) G[len].f=p; else { G[++len].l=G[x].l+1,G[len].f=G[p].f,G[p].f=G[len-1].f=len; for(i=0;i<26;i++)G[len].next[i]=G[p].next[i]; for(i=x;i&&G[i].next[ch]==p;i=G[i].f)G[i].next[ch]=len; } } void explore(int ch) { if(G[last].next[ch])++cnt; else { for(;last&&!G[last].next[ch];last=G[last].f); if(!last){last=1,cnt=0; return;} cnt=G[last].l+1; } last=G[last].next[ch],MAX=max(MAX,cnt); } }; int LCS(string S,string T) { SAM mySAM(S); for(int i=0;i<T.size();++i)mySAM.explore(T[i]-'a'); return mySAM.MAX; }
原文地址:http://blog.csdn.net/kingwolfofsky/article/details/39297275