【后缀数组求不可重叠最长重复子串】POJ 1743
来源:互联网 发布:万夫莫开贾克斯cdk淘宝 编辑:程序博客网 时间:2024/06/05 09:18
不可重叠最长重复子串(pku1743)
给定一个字符串,求最长重复子串,这两个子串不能重叠。
算法分析:
这题比上一题稍复杂一点。先二分答案,把题目变成判定性问题:判断是否存在两个长度为k 的子串是相同的,且不重叠。解决这个问题的关键还是利用height 数组。把排序后的后缀分成若干组,其中每组的后缀之间的height 值都不小于k。例如,字符串为“aabaaaab”,当k=2 时,后缀分成了4 组,如图5所示。
给定一个字符串,求最长重复子串,这两个子串不能重叠。
算法分析:
这题比上一题稍复杂一点。先二分答案,把题目变成判定性问题:判断是否存在两个长度为k 的子串是相同的,且不重叠。解决这个问题的关键还是利用height 数组。把排序后的后缀分成若干组,其中每组的后缀之间的height 值都不小于k。例如,字符串为“aabaaaab”,当k=2 时,后缀分成了4 组,如图5所示。
容易看出,有希望成为最长公共前缀不小于k 的两个后缀一定在同一组。然后对于每组后缀,只须判断每个后缀的sa 值的最大值和最小值之差是否不小于k。如果有一组满足,则说明存在,否则不存在。整个做法的时间复杂度为O(nlogn)。本题中利用height 值对后缀进行分组的方法很常用,请读者认真体会。
#define maxn 20010int wa[maxn],wb[maxn],wv[maxn],wss[maxn];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数组的值均大于0。然后要在原字符串后添加一个0号字符 所以,若原串的长度为n,则实际要进行后缀数组构建的r数组的长度应该为n+1.所以调用da函数时,对应的n应为n+1.*/void da(int *r,int *sa,int n,int m){//n要加1 int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) wss[i]=0; for(i=0;i<n;i++) wss[x[i]=r[i]]++; for(i=1;i<m;i++) wss[i]+=wss[i-1]; for(i=n-1;i>=0;i--) sa[--wss[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++) wss[i]=0; for(i=0;i<n;i++) wss[wv[i]]++; for(i=1;i<m;i++) wss[i]+=wss[i-1]; for(i=n-1;i>=0;i--) sa[--wss[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++; } return;}int rank[maxn],height[maxn];//rank[i]:i排第几;sa[i]:排第i的后缀串在哪里,互为逆运算void calheight(int *r,int *sa,int n){//n不用加1 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(){ int n; while(scanf("%d",&n) && n){ int i; int x,y; scanf("%d",&x); for(i=0;i<n-1;i++){ scanf("%d",&y); r[i] = y - x + 100;//不能出现负数 x = y; }cout<<endl; r[n-1] = 0;//总共有n-1个值 da(r,sa,n,190); calheight(r,sa,n-1); for(i=1;i<=n-1;i++) cout<<height[i]<<endl; int l = 0,r = n-1; int mid; int ans=0; while(l<=r){ mid = (l+r)>>1; int minm = sa[1]; int maxm = sa[1]; bool ok = 0; for(i=2;i<=n;i++){//不写i<=n-1的原因系这样可以处理完最后一组 if(height[i]>=mid && i!=n){ if(sa[i]>maxm)maxm = sa[i]; if(sa[i]<minm)minm = sa[i]; } else { if(maxm - minm>=mid){ ok = 1; break; } else minm = maxm = sa[i]; } } if(ok){ ans = mid; l = mid+1; } else r = mid-1; } //ans+1的原因是前面的处理是把后一个减去前一个的值,所以最后要+1个 if(ans+1<=4)printf("%d\n",0); else printf("%d\n",ans+1); } return 0;}
- poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
- 【后缀数组求不可重叠最长重复子串】POJ 1743
- POJ 1743 Musical Theme(后缀数组求不可重叠最长重复子串)
- POJ 1743 Musical Theme (后缀数组加二分求不可重叠最长重复子串)
- POJ - 1743 Musical Theme (后缀数组求不可重叠最长重复子串)
- poj 1743 字符串 后缀数组 不可重叠最长重复子串
- Poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- poj 1743 Musical Theme(不可重叠的最长重复子串,后缀数组)
- POJ 1743 Musical Theme ( 后缀数组 + 二分 不可重叠最长重复子串 )
- POJ 1743 Musical Theme 后缀数组 不可重叠最长重复子串
- 后缀数组(不可重叠最长重复子串)——POJ 1743
- POJ - 1743 - Musical Theme(后缀数组 - 不可重叠最长重复子串)
- POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])
- POJ 1743 Musical Theme(不可重叠最长重复子串 后缀数组)
- 后缀数组 不重叠最长重复子串 POJ 1743
- poj 1743 后缀数组求最长不重叠重复子串
- POJ 1743 Musical Theme (后缀数组,求最长不重叠重复子串)
- 建造者(Builder)模式
- 走进美国------个人所得税
- SqlDataSource的Selecting事件使用心得
- 走进中国------个人所得税
- Windows Sysinternals 微软官方免费的极品实用绿色小工具合集,绝对值得你收藏!
- 【后缀数组求不可重叠最长重复子串】POJ 1743
- 权力
- ubuntu11.10 nfs设置
- 列的范围控制 CHECK 约束 和 规则 (sql2005)
- 编译内核
- ExtJs xtype一览
- Apache+php+mysql的安装与配置 - 之二(Apache的文件目录配置)
- 目录拷贝–bash实现
- 个人备忘--注解