题意就是给你s1和s2,然后让你求最长的公共子串,这里的公共子串是只要s1和s2里出现了2个各字母出现次数均相等的子串,就可以认为这是公共子串了。
这题我一开始用的是二分,结果一直wa,后面看了这组数据(iamaweakishspeller ,williamshakespeare)这组数据正确应该输出18的,但是我二分的mid在9就不行了,然后就可以知道较大规模虽然满足,但是小规模却不满足,如果能用二分的话应该是大规模满足,则小规模必满足的,所以的话这题就没有单调性,就不能用二分了。然后换种思路用hash了,但是普通的hash的话,ab对应的hash值和ba对应的是不同的,因为普通的hash方法是考虑了顺序在里面了,所以我们要消去顺序的影响,那就是把每个串的26个字母出现的个数都求出来,用来hash,我用的是自然溢出法,不用自然溢出法总是wa。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const ull base=90;
int pre1[4005][26],pre2[4005][26];
string s1,s2;
unordered_map<ull,bool>mp;
int main()
{
int len1,len2;
ull ihash;
cin>>s1>>s2;
len1=s1.size();
len2=s2.size();
s1=" "+s1;
s2=" "+s2;
for(int i=1;i<=len1;i++)
{
for(int j=0;j<=25;j++)
pre1[i][j]=pre1[i-1][j];
pre1[i][s1[i]-'a']++;
}
for(int i=1;i<=len2;i++)
{
for(int j=0;j<=25;j++)
pre2[i][j]=pre2[i-1][j];
pre2[i][s2[i]-'a']++;
}
for(int len=min(len1,len2);len>=1;len--)
{
mp.clear();
for(int st=1;st<=len1-len+1;st++)
{
int ed=st+len-1;
ihash=0;
for(int i=0;i<26;i++)
ihash=ihash*base+(pre1[ed][i]-pre1[st-1][i]);
mp[ihash]=1;
}
for(int st=1;st<=len2-len+1;st++)
{
int ed=st+len-1;
ihash=0;
for(int i=0;i<26;i++)
ihash=ihash*base+(pre2[ed][i]-pre2[st-1][i]);
if(mp.count(ihash))
{
printf("%d
",len);
return 0;
}
}
}
printf("0
");
return 0;
}