码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 2774 最长公共子串

时间:2015-09-18 23:23:58      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:

对于最长公共子串,n*m的递推显然无法通过本题。

本题是后缀数组的一个基础应用,字符串的子串可以视作后缀的前缀。

我们在两个串间插入一个不在字符集的字符如‘#‘作为连接,这样做的目的是为了防止两个后缀的最长公共前缀跨过第一个字符串的末尾。

扫描Height数组,如果排名为i的字符串与排名为i-1的字符串来源于原来的2个串,则更新答案最大值。

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <string>
 5 #include <string.h>
 6 #include <stdio.h>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <set>
11 #include <cmath>
12 #include <ctime>
13 #include <cassert>
14 #include <sstream>
15 using namespace std;
16 
17 const int N=2e6+10010;
18 
19 int sa[N];
20 int t1[N],t2[N],c[N];
21 int rk[N],height[N];
22 
23 inline int cmp(int *r,int a,int b,int l){
24     return r[a]==r[b]&&r[a+l]==r[b+l];
25 }
26 char s[N];
27 void calcSA (char *s,int n,int m) {
28     int i,j,p,*x=t1,*y=t2;
29     for(i=0;i<m;i++)c[i]=0;
30     for(i=0;i<n;i++)c[x[i]=s[i]]++;
31     for(i=1;i<m;i++)c[i]+=c[i-1];
32     for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
33     for(j=1;j<=n;j<<=1){
34         p=0;
35         for(i=n-j;i<n;i++)y[p++]=i;
36         for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
37         for(i=0;i<m;i++)c[i]=0;
38         for(i=0;i<n;i++)c[x[y[i]]]++;
39         for(i=1;i<m;i++)c[i]+=c[i-1];
40         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
41         swap(x,y);
42         p=1;x[sa[0]]=0;
43         for(i=1;i<n;i++)
44             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
45         if(p>=n)break;
46         m=p;
47     }
48 }
49 
50 void calcHeight(char *s,int n) {
51     int i,j,k=0;
52     for(i=0;i<=n;i++)rk[sa[i]]=i;
53     for(i=0;i<n;i++){
54         if(k)k--; // h[i]>=h[i-1]-1
55         j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位
56         while(s[i+k]==s[j+k])k++; // 暴力计算lcp
57         height[rk[i]]=k;
58     }
59 }
60 int solveLCP(int len,int pos) {
61     int ret=0;
62     for (int i=2;i<=len;i++) {
63         if ((sa[i-1]>pos && sa[i]<pos)
64             ||(sa[i-1]<pos && sa[i]>pos)
65             )
66             ret=max(ret,height[i]);
67     }
68     return ret;
69 }
70 int main () {
71     while (scanf("%s",s)!=EOF) {
72         int n=strlen(s);
73         s[n]=#;
74         scanf("%s",s+n+1);
75         //puts(s);
76         int len=strlen(s);
77         s[len]=0;
78         calcSA(s,len+1,128);
79         calcHeight(s,len);
80         //for (int i=0;i<=len;i++) cout<<rk[i]<<" ";cout<<endl;
81         int ret=solveLCP(len,n);
82         cout<<ret<<endl;
83     }
84     return 0;
85 }

 

POJ 2774 最长公共子串

标签:

原文地址:http://www.cnblogs.com/micrari/p/4820464.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!