题意 : 给你两个字符串 , 找到其中最短的字符串,要求在串1中出现过,在串2中出现过,并且在串1中只出现过一次,在串2中只出现过一次
思路 : 将两个串拼接在一起 , 用 $ 隔开 。 我们根据 height 数组求解。
首先 , 我们要求解的字符串必然是两个串的公共子串 , 所以对于 height[i] 应该要保证 sa[i-1] 和 sa[i] 分别处于两个字符串。( 我们只用考虑后缀排序后相连的情况 , 因为如果两个后缀在sa中不相连,那么中间必然两个字符串的LCP大于这两个字符串的LCP,那么就不能保证这个字符串在两个串中只出现一次了 )
当然这样只是求得两个串的公共子串,要判断是否满足题意,那么就要判断height[i-1] 和 height[i+1] , 只有这两个最大值要小于 height[i] , height[i] 这个字符串才满足题意。否则必然在串1或者串2中出现过该串。
当然了这样求得的字符串不能保证是最短的。对于一个height[i] , 我们取的最小值应该是 max( height[i-1] , height[i+1] ) + 1 . 因为 max( height[i-1] ,height[i+1] ) 就是和其他后缀的最大LCP,那么加1之后就能保证是唯一的。
那么对于每个符合题意的height[i] 取个最小值即可。这样如果用dc3,就是O(n)的复杂度了 。
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 10005
int wa[maxn],wb[maxn],wv[maxn],wt[maxn];
typedef long long LL ;
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) wt[i]=0;
for(i=0;i<n;i++) wt[x[i]=r[i]]++;
for(i=1;i<m;i++) wt[i]+=wt[i-1];
for(i=n-1;i>=0;i--) sa[--wt[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++) wt[i]=0;
for(i=0;i<n;i++) wt[wv[i]]++;
for(i=1;i<m;i++) wt[i]+=wt[i-1];
for(i=n-1;i>=0;i--) sa[--wt[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++;
}
}
int Rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n){
int i , j , k = 0 ;
for( i=1 ; i<=n ; i++ ) Rank[sa[i]]=i;
for(i=0;i<n;i++) {
if(k)k--;
int j = sa[Rank[i]-1];
while(r[i+k]==r[j+k]) k++ ;
height[Rank[i]] = k ;
}
return;
}
char str[maxn] ;
int r[maxn] , sa[maxn] ;
int main(){
while( scanf( "%s" , str ) != EOF ) {
int l1 = strlen( str ) ;
str[l1] = '$' ;
str[l1+1] = 0 ;
scanf( "%s" , str + l1 + 1 ) ;
int len = strlen( str ) ;
for( int i = 0 ; i < len ; i ++ ) r[i] = str[i] ;
r[len] = 0 ;
da( r , sa , len + 1 , 200 ) ;
calheight( r , sa , len ) ;
int Min = INF ;
for( int i = 2 ; i <= len ; i ++ ) {
if( ( sa[i-1] - l1 ) * ( sa[i] - l1 ) < 0 && height[i] ) {
bool flag = true ;
int Max = 0 ;
if( height[i-1] >= height[i] ) {
flag = false ;
}else
Max = max( Max , height[i-1] ) ;
if( i < len && height[i+1] >= height[i] ) {
flag = false ;
}else
Max = max( Max , height[i+1] ) ;
if( flag ) {
Min = min( Min , Max + 1 ) ;
}
}
}
if( Min == INF ){
puts( "-1" ) ;
} else {
printf( "%d\n" , Min ) ;
}
}
return 0 ;
}