由于只能从b串中拆掉一段连续的,所以b串是由前面和后面2部分组成的(其中一部分可能是0,空串)。我们先预处理出pos1[i]及b串的前i个要从前向后匹配到a串的哪个位置,pos2[i]表示b串的后i个要从后向前匹配到哪个位置。然后二分拆掉的长度,去判断是否存在l,r=l+mid+1,使得pos1[l]<pos2[r],则表示此时存在拆掉这个长度mid,b串的前l和后r个是a串的不连续子串。
据说使用two-pointer可以不二分,你在b串中枚举一个l,然后找到向右边找到一个r使得pos1[l]<pos2[r]因为pos1[l-1]<pos1[l]恒成立,所以l和r都是一直向右走的,这种做法便是O(n)的
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 100010
int ans,ansl,ansr,alen,blen;
int pos1[maxl],pos2[maxl];
char a[maxl],b[maxl];
void prework()
{
memset(pos1,0,sizeof(pos1));
memset(pos2,0,sizeof(pos2));
alen=strlen(a+1);blen=strlen(b+1);
int l=1;
for(int i=1;i<=blen;i++)
{
while(l<=alen && a[l]!=b[i])
l++;
pos1[i]=l;
if(l<=alen)
l++;
}
pos1[0]=0;pos2[blen+1]=alen+1;
int r=alen+1;
for(int i=blen;i>=1;i--)
{
while(l>=1 && a[l]!=b[i])
l--;
pos2[i]=l;
if(l>=1)
l--;
}
}
bool jug(int mid)
{
int l=0,r=mid+1;
while(r<=blen+1)
{
if(pos1[l]<pos2[r])
return true;
l++;r++;
}
return false;
}
void mainwork()
{
int l=0,r=blen,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(jug(mid))
r=mid;
else
l=mid;
}
if(jug(l))
ans=l;
else if(jug(r))
ans=r;
else
ans=r+1;
l=0,r=ans+1;
ansl=0;ansr=blen+1;
while(r<=blen+1)
{
if(pos1[l]<pos2[r])
{
ansl=l;ansr=r;
break;
}
l++;r++;
}
}
void print()
{
if(ans==blen)
printf("-");
else
{
for(int i=1;i<=ansl;i++)
printf("%c",b[i]);
for(int i=ansr;i<=blen;i++)
printf("%c",b[i]);
}
printf("\n");
}
int main()
{
while(~scanf("%s%s",a+1,b+1))
{
prework();
mainwork();
print();
}
return 0;
}