POJ 2774

用后缀数组求最长前缀
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <math.h>

#define MAXN 200010

using namespace std;

int m1[MAXN],m2[MAXN];
char s[2*MAXN];
int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n;
void Build_Sa(int n){//m是基数排序字符的长度 
	int m;
	int i,*x=t,*y=t2;
	m=(n<256?256:n);
	//基数排序
	for(i=0;i<m;i++) c[i]=0;
	for(i=0;i<n;i++) c[x[i]=s[i]]++;
	for(i=1;i<m;i++) c[i]+=c[i-1];
	for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
	for(int k=1;k<=n;k<<=1){
		int p=0;
		//直接利用sa数组排序第二关键字
		for(i=n-k;i<n;i++) y[p++]=i;
		for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
		//基数排序第一关键字
		for(i=0;i<m;i++) c[i]=0;
		for(i=0;i<n;i++) c[x[y[i]]]++;
		for(i=0;i<m;i++) c[i]+=c[i-1];
		for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
		//根据sa和y数组计算新的x数组
		swap(x,y);
		p=1;x[sa[0]]=0;
		for(i=1;i<n;i++)
			x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
		if(p>=n) break;//以后即使继续倍增,sa也不会改变,退出下次基数排序的最大值 
		m=p;//这个m是一直在变的,所以m只需要给出第一次基数排序的长度就可以了           
	}
}
int rank[MAXN],height[MAXN];
void getHeight(int n){
	int i,j,k=0;
	for(i=0;i<n;i++) rank[sa[i]]=i;
	for(i=0;i<n;i++){
		if(k) k--;
	 	j=sa[rank[i]-1];
		while(s[i+k]==s[j+k]) k++;
		height[rank[i]]=k;
	}
}

int main(){
	int m,n,i,j,k,l1,l2;
	char str2[MAXN];
	while(scanf("%s%s",s,str2)!=EOF){
		//构造"str#str1"
        l1=strlen(s);
        l2=strlen(str2);
        strcat(s,"*");
        strcat(s,str2);
        n=strlen(s);
		puts(s);
		Build_Sa(n);

		getHeight(n);

		int p,q,ans;
		for(i=1,ans=0;i<n;i++){
			/*
			if(sa[i]-l2>=0) p=1;
			else p=-1;
			if(sa[i-1]-l2<0) q=1;
			else q=-1;
			弄清楚sa数组里面的含义
			http://www.nocow.cn/index.php/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84 
			*/
			if((__int64)(sa[i]-l1)*(sa[i-1]-l1)<0 && ans<height[i]) ans=height[i];
		}
		printf("%d\n",ans);
		
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值