哈希求最长公共子串
给定 个字符串,长度总和不超过 ,试求这 个字符串的最长公共子串长度。
对于这种求最长公共子串的问题,我们可以用哈希解决。
不难发现,最长公共子串具有单调性,这提示我们二分答案。
对于二分的长度 ,考虑如何检验。
首先有一个非常暴力的想法,将所有字符串的长度为 的子串全部取出,如果发现其中一个子串在所有字符串中均出现过,那么检验成功。
具体而言,定义一个二元组 分别表示子串和所处字符串编号,然后进行去重,因为一个字符串可能贡献若干相同二元组,如 可以贡献 个 的二元组。
去重后,将所有子串相同的二元组放在一起,比如 ,如果一个子串相等的连续段中有 个,那么即可说明所有字符串都可以出现该子串,进而说明长度 可行。
截止这里,我们发现整个算法最大的瓶颈就是子串的储存与快速比对,这里将字符串换成对应的哈希值即可。
至于如何将哈希值相等二元组放在一起,直接对二元组进行排序,去重即可。
P5546 [POI2000] 公共串
这就是一道典型的最长公共子串的题目,思路同上,下面给出代码。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; #define PUI pair<ULL,int> const int N=2100; int n; string s[6]; int len[6]; ULL p[N],ha[6][N]; vector<PUI> g; ULL get(int id,int l,int r) { return ha[id][r]-ha[id][l-1]*p[r-l+1]; } int check(int mid) { g.clear(); for(int i=1;i<=n;i++) { for(int j=1;j+mid-1<=len[i];j++) { g.push_back({get(i,j,j+mid-1),i}); } } sort(g.begin(),g.end());//排序 g.erase(unique(g.begin(),g.end()),g.end());//去重 int cnt=0; ULL nha=0; for(int i=0;i<g.size();i++) { if(cnt==0) {nha=g[i].first; cnt++;} else { if(nha==g[i].first) { cnt++; if(cnt==n) return 1; } else { cnt=1; nha=g[i].first; } } } return 0; } void Sol() { cin>>n; for(int i=1;i<=n;i++) { cin>>s[i]; len[i]=s[i].size(); s[i]=" "+s[i]; for(int j=1;j<=len[i];j++) ha[i][j]=ha[i][j-1]*13331+int(s[i][j]-'a'); } if(n==1) { cout<<len[1]; return ; } int l=0,r=max({len[1],len[2],len[3],len[4],len[5]}); while(l<r) { int mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; } cout<<l<<endl; } int main(){ p[0]=1; for(int i=1;i<=2000;i++) p[i]=p[i-1]*13331; Sol(); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库