题意:给定a和b两个字符串,有b匹配a在允许有两个字母不匹配而其他全匹配的情况下,找出第一个匹配的位置,若不能匹配,返回-1;
simple input
3
aaabcd
abee
aaaaaa
aaaaa
aaaaaa
aabbb
simple output
Case #1: 2
Case#2: 0
Case#3: -1
解题思路:
首先将b串接到a串的后面,利用LCP算法,进行匹配,中间最多有两次匹配不成功。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long int ULL;
const int SIZE = 100003;
const int SEED = 13331;
const int maxn = 600100;
char s[maxn];
ULL H[maxn];
ULL XL[maxn];
int len;
void build(char *s) //求出字符串哈希值函数模板O(n)
{
len=strlen(s);
H[len]=0;
XL[0]=1;
for (int i=len-1; i>=0; i--)
{
H[i]=H[i+1]*SEED+s[i];
XL[len-i]=XL[len-i-1]*SEED;
}
}
ULL hash(int i,int L) //返回以i为开头的长度为L的字符串的哈希值(比较两个字符串的哈希值是否相等就可以判定两个字符串是不是相等)O(lgn)
{
return H[i]-H[i+L]*XL[L];
}
int lcp(int i,int j)//二分,返回求取的以i和j开头的字符串的最大匹配的长度
{
int l=0,r=min(len-i,len-j);
int res=0;
while (l<=r)
{
int mid=(l+r)/2;
if (hash(i,mid)==hash(j,mid))
{
res=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
return res;
}
char A[maxn],B[maxn];
int main()
{
int T;
int cas=0;
scanf("%d",&T);
while (T--)
{
cas++;
scanf("%s%s",A,B);
int len1=strlen(A);
int len2=strlen(B);
if (len1<len2)
{
printf("Case #%d: -1\n",cas);
continue;
}
int n=len1+len2+1;//合并两个字符串,中间加上一个保证不会在这两个串中出现的字符防止特殊情况
for (int i=0; i<len1; i++) s[i]=A[i];
for (int i=0; i<len2; i++) s[len1+1+i]=B[i];
s[len1]='$';
s[n]=0;
build(s);
int ans=-1;
for (int i=0; i<=len1-len2; i++)
{
int st=i;
int ed=len1+1;
int tmp=lcp(st,ed);
st+=tmp;
ed+=tmp;
if (ed>=n)//匹配到末尾了,下同
{
ans=i;
break;
}
st++;
ed++;//第一次匹配不成功
if (ed>=n)
{
ans=i;
break;
}
tmp=lcp(st,ed);
st+=tmp;
ed+=tmp;
if (ed>=n)
{
ans=i;
break;
}
st++;
ed++;//第二次匹配不成功
if (ed>=n)
{
ans=i;
break;
}
tmp=lcp(st,ed);
st+=tmp;
ed+=tmp;
if (ed>=n)
{
ans=i;
break;
}
}
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}