3508. 最长公共子串
摘要
Title: 3508. 最长公共子串
Tag: 二分、字符串哈希
Memory Limit: 64 MB
Time Limit: 1000 ms
Powered by:NEFU AB-IN
3508. 最长公共子串
-
题意
给定两个字符串,求这两个字符串的不包含数字的最长公共子串的长度。
-
思路
首先可以采用dp的方法暴力来做,复杂度为
其次考虑二分,因为答案具有单调性,所以,可以在二分时将一个串的长度为mid的串的哈希值存在哈希表中,扫另一个串时进行判断有没有
最后不包含数字这一条,可以将每个串的数字各替换成不同的符号 -
代码
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
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10, INF = 0x3f3f3f3f, P = 13331;
ULL hs[N], ps[N], ht[N], pt[N];
string s, t;
ULL gets(int l, int r)
{
return hs[r] - hs[l - 1] * ps[r - l + 1];
}
ULL gett(int l, int r)
{
return ht[r] - ht[l - 1] * pt[r - l + 1];
}
bool check(int x)
{
unordered_set <int> us;
for(int i = 1; i + x - 1 < SZ(s); ++ i){
us.insert(gets(i, i + x - 1));
}
for(int i = 1; i + x - 1 < SZ(t); ++ i){
if(us.count(gett(i, i + x - 1))) return true;
}
return false;
}
signed main()
{
IOS;
cin >> s >> t;
s = " " + s;
t = " " + t;
for(int i = 1; i < SZ(s); ++ i){
if(s[i] >= '0' && s[i] <= '9') s[i] = '#';
}
for(int i = 1; i < SZ(t); ++ i){
if(t[i] >= '0' && t[i] <= '9') t[i] = '$';
}
ps[0] = pt[0] = 1;
for(int i = 1; i < SZ(s); ++ i){
ps[i] = ps[i - 1] * P;
hs[i] = hs[i - 1] * P + s[i];
}
for(int i = 1; i < SZ(t); ++ i){
pt[i] = pt[i - 1] * P;
ht[i] = ht[i - 1] * P + t[i];
}
int l = 0, r = min(SZ(s), SZ(t));
while(l < r){
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << r;
return 0;
}