题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403
banana cianaic
3
题意:
求两个字符串的最长公共子串长度!
代码如下:
#include <cstdio> #include <cstring> const int N = 100017*2; int wa[N], wb[N], wv[N], ws[N]; int rank[N]; //名次数组 int height[N]; //排名相邻的两个后缀的最长公共前缀 char str[N]; int s[N], sa[N]; //sa为后缀数组,n个后缀从小到大进行排序之后把排好序的后缀的开头位置 int Max(int a, int b) { return a > b ? a:b; } int Min(int a, int b) { return a < b ? a:b; } int cmp(int *r, int a, int b, int l) { return r[a]==r[b] && r[a+l]==r[b+l]; } //get_sa函数的参数n代表字符串中字符的个数,这里的n里面是包括人为在字符串末尾添加的那个0的 //get_sa函数的参数m代表字符串中字符的取值范围,是基数排序的一个参数, //如果原序列都是字母可以直接取128, //如果原序列本身都是整数的话,则m可以取比最大的整数大1的值。 void get_sa(int *r, int *sa, int n, int m) //倍增算法 { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) ws[i]=0; for(i=0; i<n; i++) ws[x[i]=r[i]]++; for(i=1; i<m; i++) ws[i]+=ws[i-1]; for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i; //对长度为1的字符串排序 for(p=1,j=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++) ws[i]=0; for(i=0; i<n; i++) ws[wv[i]]++; for(i=1; i<m; i++) ws[i]+=ws[i-1]; for(i=n-1; i>=0; i--) sa[--ws[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++; //更新rank数组 } return; } void get_height(int *r, int *sa, 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++); return; } int main() { while(~scanf("%s",str)) { int len = strlen(str); str[len] = '~'; scanf("%s",str+len+1); int LEN = strlen(str); for(int i = 0; i < LEN; i++) { s[i] = str[i]-'a'+1; } s[LEN] = 0; get_sa(s,sa,LEN,270); get_height(s,sa,LEN); int ans = 0; for(int i = 2; i < LEN; i++) { if(height[i] > ans) { if((sa[i-1]<len&&sa[i]>len) || (sa[i-1]>len&&sa[i]<len)) ans = height[i]; } } printf("%d\n",ans); } return 0; }
HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)
原文地址:http://blog.csdn.net/u012860063/article/details/44063889