您的位置:首页 > 其它

SPOJ - LCS Longest Common Substring 后缀自动机

2017-03-04 18:54 357 查看


Longest Common Substring

 SPOJ
- LCS

A string is finite sequence of characters over a non-empty finite set Σ.
In this problem, Σ is the set of lowercase letters.
Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.
Now your task is simple, for two given strings, find the length of the longest common substring of them.
Here common substring means a substring of two or more strings.

Input

The input contains exactly two lines, each line consists of no more than 250000 lowercase letters, representing a string.

Output

The length of the longest common substring. If such string doesn't exist, print "0" instead.

Example

Input:
alsdfkjfjkdsal
fdjskalajfkdsla

Output:
3

Notice: new testcases added
Source
SPOJ - LCS

My Solution
题意:求两个字符串的最长公共子串。

后缀自动机

看了很久 WJMZBMR 讲后缀自动机的ppt才大致把后缀自动机搞懂^_^,

此外附上两个比较好的讲后缀自动机的博客 后缀自动机 模版后缀自动机讲解

这题直接用一个字符串建立后缀自动机,然后用另一个串在自动机上跑即可,操作和AC自动机有点类似,

只是AC自动机匹配失败的时候用的fail指针,而这里用pre树跳转。

复杂度 O(n)

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 2*2.5e5 + 8;

string s;
struct SAM{
int ch[maxn][26], pre[maxn], val[maxn];
int last, tot;
void init(){
last = tot = 0;
memset(ch[0], -1, sizeof ch[0]);
pre[0] = -1; val[0] = 0;
}
void extend(int c){
int p = last, np = ++tot;
val[np] = val[p] + 1;
memset(ch[np], -1, sizeof ch[np]);
while(~p && ch[p][c] == -1) ch[p][c] = np, p = pre[p];
if(p == -1) pre[np] = 0;
else{
int q = ch[p][c];
if(val[q] != val[p] + 1){
int nq = ++tot;
memcpy(ch[nq], ch[q], sizeof ch[q]);
val[nq] = val[p] + 1;
pre[nq] = pre[q];
pre[q] = pre[np] = nq;
while(~p && ch[p][c] == q) ch[p][c] = nq, p = pre[p];
}
else pre[np] = q;
}
last = np;
}
int _find(const string &s){
int sz = s.size(), u = 0, tmp = 0, c, i, res = 0;
for(i = 0; i < sz; i++){
c = s[i] - 'a';
if(~ch[u][c]) tmp++, u = ch[u][c];
else{
while(~u && ch[u][c] == -1) u = pre[u];
if(~u) tmp = val[u] + 1, u = ch[u][c];
else tmp = 0, u = 0;
}
res = max(res, tmp);
}
return res;
}
} sam;

int main()
{
#ifdef LOCAL
freopen("11.in", "r", stdin);
//freopen("11.out", "w", stdout);
int T = 2;
while(T--){
#endif // LOCAL
ios::sync_with_stdio(false); cin.tie(0);

int n, i;
cin >> s;
n = s.size();
sam.init();
for(i = 0; i < n; i++) sam.extend(s[i] - 'a');
cin >> s;
cout << sam._find(s) << endl;;

#ifdef LOCAL
cout << endl;
}
#endif // LOCAL
return 0;
}


Thank you!

                                                           
                                                                                 ------from ProLights
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: