目录
前言
学习了之前所发的有关字符串哈希的相关讲解,相信有一部分同学已经按捺不住赶紧上手刷上那么几题了呢!然后本蒟蒻在今天考完机考,马上就拿上了电脑开启了相关的刷题,没想到一个普及组的题目刷了有一个半小时之久,利用昨天一位很厉害的学长说的话:菜是原罪!如果不知道字符串哈希是什么的uu们点击这里:字符串哈希(嘻嘻)!
题目详情
原题是一个英文题目,但是洛谷官网把它翻译了,这是本题的链接:洛谷题目p2957
简单分析
因为已经有了字符串哈希的基础,所以此题,其实只用算出字符串a的前缀和后缀以及字符串b的前缀和后缀的哈希值就可以了,然后进行两次比较,最终得出最长的重复字串个数!
注意事项
不知道看到这的同学们,在思考的时候会不会想,我们这个题目最终可不可以利用二分答案的方法去找到最终的那个最长的答案,我刚开始也是那么想的,结果一个小时都在找此题利用二分的错误在哪。大家可以再自习读读题目,由于题目的特殊性,此题都是在求前缀和后缀,如果用二分的话,那就是一个在找是否存在最长重复子串的问题了,这和我们去计算后缀的哈希值的思想是完全不符合的,最终当然不会得到正确的答案啦!
完整代码
#include<bits/stdc++.h>
using namespace std;
int mod=13331,k=26; //利用mod防止数字溢出,k表示在26进制下的哈希值
string a,b;
int sum=0;
long long a1[100]; //记录a字串的哈希值
long long b1[100]; //记录b字串的哈希值
//计算前缀的哈希值
long long hash1(string s,int len)
{
long long ans1=0;
for(int i=0;i<len;i++)
{
ans1=(ans1*k%mod+(s[i]-'0'))%mod;
}
return ans1;
}
//计算后缀的哈希值
long long hash2(string s,int len,int length)
{
long long ans2=0;
for(int i=length-len;i<length;i++)
{
ans2=(ans2*k%mod+(s[i]-'0'))%mod;
}
return ans2;
}
int main()
{
cin>>a>>b;
int len1=a.length();
int len2=b.length();
//最终答案一定不会超过两字串较小长度的那一个长度
int minl=min(len1,len2);
//sum记录下最终的答案
int sum=0;
//sum1 表示a的前缀与b的后缀最长相等的个数
//sum2 表示b的前缀与a的后缀最长相等的个数
int sum1=0,sum2=0;
//计算a的前缀和b的后缀。
for(int i=1;i<=minl;i++)
{
a1[i]=hash1(a,i);
b1[i]=hash2(b,i,len2);
if(a1[i]==b1[i]) sum1=i;
}
//计算a的后缀和b的前缀
for(int i=1;i<=minl;i++)
{
b1[i]=hash1(b,i);
a1[i]=hash2(a,i,len1);
if(a1[i]==b1[i]) sum2=i;
}
//输出sum1,sum2的最大的那一个
sum=max(sum1,sum2);
cout<<sum<<endl;
}
AC凭证
水话
本蒟蒻已经分专栏了哦,相信大家会更加清晰的找到对应的块进行阅读,然后呢封面是自己设计的,虽然比较丑,但是嘛我觉得还是很可爱的哈哈哈!