概述
题意
题目
即求k(k<=1e5)个串的最长公共子串的长度,
字符集大小1e5,k个串的总长度不超过1e5
思路来源
乱搞AC
题解
大概是一个poj3294的后缀数组原题,
首先将k个串用k-1个特殊字符(这里用1e5+1)连接到一起,
注意不能用k个,不然会导致二分的答案长度+1,这样构造的新串长度2e5
考虑二分答案长度x,忽略height<x的,将height>=x的尺取,
然后,判断尺取的每一段,起始下标的并是否为k
对于每个字符,bel[i]记录第i个字符位于哪段
另一种做法是考虑哈希,二分答案长度x,
把每个串内长度为x的子串的哈希值丢进set,
把set内的每个值丢进map进行+1,判断map内是否存在为k的值
代码
class Solution {
public:
struct SuffixArray{
#define N 200005
int *x,*y,n,m,s[N+5],X[N+5],Y[N+5],c[N+5],sa[N+5],height[N+5],Rank[N+5];
int bel[N+5];
bool vis[N+5];
void get_sa(int _n,int _m=100002){
n=_n;
m=_m;
x=X,y=Y;
for (int i=0;i<n;++i) x[i]=s[i];
for (int i=0;i<m;++i) c[i]=0;
for (int i=0;i<n;++i) ++c[x[i]];
for (int i=1;i<m;++i) c[i]+=c[i-1];
for (int i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
for (int k=1;k<=n;k<<=1){
int p=0;
for (int i=n-k;i<n;++i) y[p++]=i;
for (int i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
for (int i=0;i<m;++i) c[i]=0;
for (int i=0;i<n;++i) ++c[x[y[i]]];
for (int i=1;i<m;++i) c[i]+=c[i-1];
for (int i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for (int i=1;i<n;++i)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&((sa[i-1]+k<n?y[sa[i-1]+k]:-1)==(sa[i]+k<n?y[sa[i]+k]:-1))?p-1:p++;
if (p>n) break;
m=p;
}
}
void get_height(){
for (int i=0;i<n;++i) Rank[sa[i]]=i;
int k=0;height[0]=0;
for (int i=0;i<n;++i){
if (!Rank[i]) continue;
if (k) --k;
int j=sa[Rank[i]-1];
while (i+k<n && j+k<n && s[i+k]==s[j+k]) ++k;
height[Rank[i]]=k;
}
}
bool ok(int sz,int z){
//printf("sz:%d z:%dn",sz,z);
int tot=0;
vector<int>tmp;
for(int i=1;i<n;++i){
// printf("i:%d heigh:%dn",i,height[i]);
if(height[i]<sz){
for(auto &v:tmp){
vis[v]=0;
}
if(tot==z){
return 1;
}
tot=0;
}
else{
//printf("i:%d sai:%d sai-1:%dn",i,sa[i],sa[i-1]);
int pa=sa[i],pb=sa[i-1];
//printf("bpa:%d bpb:%dn",bel[pa],bel[pb]);
if(bel[pa]<=z && !vis[bel[pa]]){
vis[bel[pa]]=1;
tot++;
tmp.push_back(bel[pa]);
}
if(bel[pb]<=z && !vis[bel[pb]]){
vis[bel[pb]]=1;
tot++;
tmp.push_back(bel[pb]);
}
//printf("tot:%dn",tot);
}
}
for(auto &v:tmp){
vis[v]=0;
}
//printf("tot:%dn",tot);
return tot==z;
}
void PR(){
for(int i=0;i<n;++i)
printf("Rank[%d]:%dn",i,Rank[i]);
for(int i=0;i<n;++i)
printf("sa[%d]:%d ",i,sa[i]);
for(int i=0;i<n;++i)
printf("height[%d]:%dn",i,height[i]);
}
}sa;
int longestCommonSubpath(int col, vector<vector<int>>& a) {
int z=a.size();
int c=0,l=0,r=0;
for(int i=0;i<z;++i){
int sz=a[i].size();
r=max(r,sz);
for(int j=0;j<sz;++j){
int v=a[i][j];
sa.s[c]=v;
sa.bel[c]=i;
c++;
}
if(i!=z-1){
sa.s[c]=100001;
sa.bel[c]=z+1;
c++;
}
}
sa.get_sa(c,100002);
sa.get_height();
//sa.PR();
while(l<=r){
int mid=(l+r)/2;
if(sa.ok(mid,z)){
l=mid+1;
}
else{
r=mid-1;
}
}
return r;
}
};
最后
以上就是冷傲白猫为你收集整理的leetcode 5803. 最长公共子路径(k-最长公共子串问题)的全部内容,希望文章能够帮你解决leetcode 5803. 最长公共子路径(k-最长公共子串问题)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复