后缀数组练习3:连续重复子串

比前面两个练习题更加简单,只要知道height数组的性质就可以了

1469: 后缀数组3:连续重复子串

poj2774

时间限制: 1 Sec  内存限制: 128 MB
提交: 101  解决: 57
[提交] [状态] [讨论版] [命题人:admin]
题目描述

【问题描述】

求两个字符串的最长公共子串。(长度不超过100000,都是小写字母)

【样例】
输入:

yeshowmuchiloveyoumydearmotherreallyicannotbelieveit

yeaphowmuchiloveyoumydearmother
输出:

27 

不多说,这道题的思路我会引用罗穗骞大佬的论文当中的讲解

 

简单来说,就是把两个字符串合并,然后用get_he找到他们的最长重复子串,但是要判断是sa是分别属于两个不同的子串里面的

代码实现

 1 /*先用个分隔符将两个字符串连接起来,再用后缀数组求出height数组的值,
 2 找出一个height值最大并且i与i-1的sa值分别在两串字符中就好*/
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #include<cmath>
 8 #include<iostream>
 9 using namespace std;
10 int sa[200020],Rank[200020],rsort[200020];
11 int cnt[200020],pos[200020],height[200020];
12 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
13 char a[200020],b[200020];
14 void get_sa(int n,int m) 
15 {
16     int k=1,p=0,len;
17     for(int i=1;i<=n;i++) Rank[i]=a[i];
18     memset(rsort,0,sizeof(rsort));
19     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
20     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
21     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
22     for(int k=1;k<n;k<<=1)
23     {
24         len=0;
25         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
26         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
27         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
28         memset(rsort,0,sizeof(rsort));
29         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
30         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
31         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
32         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
33         p=1; Rank[sa[1]]=1;
34         for(int i=2;i<=n;i++)
35         {
36             if(!cmp(sa[i],sa[i-1],k)) p++;
37             Rank[sa[i]]=p;
38         }
39         m=p;
40     }
41     a[0]=0; sa[0]=0;
42 }
43 void get_he(int n)
44 {
45     int j,k=0;
46     for(int i=1;i<=n;i++)
47     {
48         j=sa[Rank[i]-1];
49         if(k) k--;
50         while(a[j+k]==a[i+k]) k++;
51         height[Rank[i]]=k;
52     }
53 }
54 int main()
55 {
56     scanf("%s",a+1); scanf("%s",b+1);
57     int n=strlen(a+1),m=strlen(b+1);
58     a[n+1]='T';/*分隔符*/
59     for(int i=n+2;i<=n+m+1;i++) a[i]=b[i-n-1];/*目前总长度为n+m+1,合并字符串的操作*/
60     get_sa(n+m+1,256); get_he(n+m+1);/*一串的ASCII码为128,两串就是256*/
61     int ans=0;
62     for(int i=2;i<=n+m+1;i++)
63         if((sa[i-1]<=n && sa[i]>n+1) || (sa[i-1]>n+1 && sa[i]<=n))/*保证sa分别在两串当中*/
64             ans=max(ans,height[i]);/*更新最大值*/
65     printf("%d\n",ans);
66     return 0;
67 }
Tristan Code

转载于:https://www.cnblogs.com/Tristanjiang/p/11381930.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值