1 学习别人的模板
2 列出两种情况
(1)代码一是两个字符串的最长公共子串poj2774
(2)代码二是假设求多个字符串中某两个字符串的最长公共子串
其中(2)没有题目,自己编的,为了便于重点理解:字符串组合时中间插入的字符对应的数应该是与输入的字符对应的ASC码不一样的数字,所以如果进行多个字符串的组合而插入多个间隔字符,那这些间隔字符应该也互相不同。
(
①代码一中 fir[k++]=31,对应代码二中 r[k++]=bian++; 数组名无所谓、注意的改变是31变为bian++。
②代码一中 da(r,k+1,31),对应代码二中 GetSa(r,k+1,bian); 函数名无所谓、注意的改变是31变为bian
)
3
注意,len是字符串实际长度(不补0的情况下):sa[],下标是该后缀的名次(1到len),值是该后缀的首字符在字符串中的位置(0到len-1);rank_[],下标是该后缀首字符在字符串中的位置(0到len-1),值是该后缀的名次(1到len);heigh[],下标是该后缀的名次(1到len),值是sa[i]与sa[i-1]的公共前缀长度,且heigh[1]是第一名次的后缀与第零名次后缀的公共前缀长度,因为第零名次后缀不存在所以heigh[1]也没有意义。
4
除了拿出来的几个函数,注意代入函数的语句:
da(r,k+1,31);//注意K+1
calHeight(r,k);
5
代码一:
#include
#include
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int MAX = 200050;
char fir[MAX],sec[MAX];
int sa[MAX], rank[MAX], height[MAX];
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int *r, int n, int m) // 倍增算法0(nlgn)。
{
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
for(j = 1, p = 1; p < n; j *= 2, m = p)
{
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 ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[wv[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)
{
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p ++;
}
}
}
void calHeight(int *r, int n) // 求height数组。
{
int i, j, k = 0;
for(i = 1; i <= n; i ++) rank[sa[i]] = i;
for(i = 0; i < n; height[rank[i ++]] = k)
{
for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
}
}
int main()
{
int r[MAX];
int len1,len2,k,maxx;
while(~scanf("%s %s",fir,sec)){
len1=strlen(fir);
len2=strlen(sec);
k=0;
maxx=0;
for(int i=0;imaxx){
if((sa[i-1]len1)||(sa[i]len1))
maxx=height[i];
}
}
cout<
6
代码二
input::
3
aabbaabb
abbababb
bbbbbabb
0
output::
4
abba
#include
#include
#include
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
//r[] 下标是字符位置从0开始;s[] 下标是名次从1开始、值是首字符位置从0开始;heigh[] 下标是名次从1开始、值是第i个名次的后缀和第i-1个名次的后缀的最长公共前缀长度(且heigh[1]没有意义);rank[] 下标是首字符位置从0开始、值是名次从1开始。
const int MAX = 800050;
char fir[MAX];
char scan[MAX];
int r[MAX];
int len[5000];
int sa[MAX], rank[MAX], height[MAX];
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
}
void GetSa(int *r, int n, int m) // 倍增算法0(nlgn)。
{
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
for(j = 1, p = 1; p < n; j *= 2, m = p)
{
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 ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[wv[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)
{
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p ++;
}
}
}
void GetHeight(int *r, int n) // 求height数组。
{
int i, j, k = 0;
for(i = 1; i <= n; i ++) rank[sa[i]] = i;
for(i = 0; i < n; height[rank[i ++]] = k)
{
for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
}
}
int main()
{
int t;
while(~scanf("%d",&t)&&t){
int k=0;
int len_k=0;
int bian=30;
char com;
char temp=getchar();
for(int i=1;i<=t;i++){
while(scanf("%c",&com)){
if(com!='\n') r[k++]=com-'a'+1;
else {
r[k++]=bian++;
len[len_k++]=k-1;
break;
}
}
}
fir[k]=0;
GetSa(r,k+1,bian);
GetHeight(r,k);
int maxx=0;
int tem=0;
for(int i=2;imaxx){
for(int j=0;jlen[j]&&sa[i-1]len[j]&&sa[i]