题目简介
给你 2 个字符串(可能包括数字以及标点),长度不超过 50124,请你求出最长的连续的公共子序列。
说明
不知道是不是数据改了,导致这个似乎是n^2的算法也能暴力过去:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string a, b;
int len, maxl = 0;
cin >> a >> b;
for (int i = 0; a[i]; ++i)
for (int j = 0; b[j]; ++j)
{
len = 0;
while (a[i] == b[j] && a[i] && b[j])
{
++i; ++j; ++len;
if (a[i] != b[j] || !a[i] || !b[j])
{
--i; --j;
break;
}
}
maxl = max(maxl, len);
}
printf("%d\n", maxl);
return 0;
}
不过仅仅满足于暴力还是不行的……这里考虑到数据太大,采用了后缀数组+高度数组的办法。不知道哈希是不是也可以?
顺带一提,string的size()方法返回unsigned int……转成int后好像会-1,被坑惨了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100200;
int n, k, ans;
string s, t;
int sa[maxn], rk[maxn], tmp[maxn], lcp[maxn];
bool cmp(int i, int j)
{
if (rk[i] != rk[j]) return rk[i] < rk[j];
int ri = i + k <= n ? rk[i + k] : -1;
int rj = j + k <= n ? rk[j + k] : -1;
return ri < rj;
}
void construct_sa()
{
n = (int)s.size();
for (int i = 0; i <= n; i++)
{
sa[i] = i;
rk[i] = i < n ? s[i] : -1;
}
for (k = 1; k <= n; k <<= 1)
{
sort(sa, sa+n+1, cmp);
tmp[sa[0]] = 0;
for (int i = 1; i <= n; i++)
tmp[sa[i]] = tmp[sa[i-1]] + cmp(sa[i-1], sa[i]);
for (int i = 0; i <= n; i++)
rk[i] = tmp[i];
}
}
void construct_lcp()
{
n = (int)s.size();
for (int i = 0; i <= n; i++)
rk[sa[i]] = i;
int h = 0;
lcp[0] = 0;
for (int i = 0; i < n; i++)
{
int j = sa[rk[i]-1];
if (h > 0) --h;
for (; j+h < n && i+h < n; ++h)
if (s[j+h] != s[i+h]) break;
lcp[rk[i]-1] = h;
}
}
int main()
{
cin >> s >> t;
int len = (int)s.size();
s += ' ' + t;
construct_sa();
construct_lcp();
for (int i = 0; i < s.size(); ++i)
if ((sa[i] < len) != (sa[i+1] < len))
ans = max(ans, lcp[i]);
printf("%d\n", ans);
return 0;
}