根据罗的论文,两个串的中间要加一个ascii码比任何字母都小的字符
最长公共子串(pku2774,ural1517)
给定两个字符串A 和B,求最长公共子串。
算法分析:
字符串的任何一个子串都是这个字符串的某个后缀的前缀。求A 和B 的最长公共子串等价于求A 的后缀和B 的后缀的最长公共前缀的最大值。如果枚举A和B 的所有的后缀,那么这样做显然效率低下。由于要计算A 的后缀和B 的后缀的最长公共前缀,所以先将第二个字符串写在第一个字符串后面,中间用一个没有出现过的字符隔开,再求这个新的字符串的后缀数组。观察一下,看看能不能从这个新的字符串的后缀数组中找到一些规律。以A=“aaaba”,B=“abaa”为例,如图 所示。
那么是不是所有的height 值中的最大值就是答案呢?不一定!有可能这两个后缀是在同一个字符串中的, 所以实际上只有当suffix(sa[i-1]) 和suffix(sa[i])不是同一个字符串中的两个后缀时,height[i]才是满足条件的。而这其中的最大值就是答案。记字符串A 和字符串B 的长度分别为|A|和|B|。求新的字符串的后缀数组和height 数组的时间是O(|A|+|B|),然后求排名相邻但原来不在同一个字符串中的两个后缀的height 值的最大值, 时间也是O(|A|+|B|),所以整个做法的时间复杂度为O(|A|+|B|)。时间复杂度已经取到下限,由此看出,这是一个非常优秀的算法。
#define maxn 211111
int wa[maxn],wb[maxn],wv[maxn],wss[maxn];//论文模板的ws竟然跟g++里的关键字冲突!
int r[maxn],sa[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b] && r[a+l]==r[b+l];}
/*【倍增算法O(nlgn)】待排序的字符串放在r 数组中,从r[0]到r[n-1],长度为n,且最大值小于m
使用倍增算法前,需要保证r数