题意
题目
即求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的值
代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123class 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内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复